diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 04cd0d29b76d1..4dc48e657542b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -47,8 +47,6 @@ /x-pack/test/functional/apps/lens @elastic/kibana-vis-editors /x-pack/test/api_integration/apis/lens/ @elastic/kibana-vis-editors /test/functional/apps/visualize/ @elastic/kibana-vis-editors -/src/plugins/unified_field_list/ @elastic/kibana-vis-editors -/test/api_integration/apis/unified_field_list/ @elastic/kibana-vis-editors # Application Services /examples/bfetch_explorer/ @elastic/kibana-app-services @@ -784,6 +782,9 @@ packages/core/integrations/core-integrations-browser-mocks @elastic/kibana-core packages/core/lifecycle/core-lifecycle-browser @elastic/kibana-core packages/core/lifecycle/core-lifecycle-browser-internal @elastic/kibana-core packages/core/lifecycle/core-lifecycle-browser-mocks @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-server @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-server-internal @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-server-mocks @elastic/kibana-core packages/core/logging/core-logging-server @elastic/kibana-core packages/core/logging/core-logging-server-internal @elastic/kibana-core packages/core/logging/core-logging-server-mocks @elastic/kibana-core @@ -807,6 +808,9 @@ packages/core/plugins/core-plugins-base-server-internal @elastic/kibana-core packages/core/plugins/core-plugins-browser @elastic/kibana-core packages/core/plugins/core-plugins-browser-internal @elastic/kibana-core packages/core/plugins/core-plugins-browser-mocks @elastic/kibana-core +packages/core/plugins/core-plugins-server @elastic/kibana-core +packages/core/plugins/core-plugins-server-internal @elastic/kibana-core +packages/core/plugins/core-plugins-server-mocks @elastic/kibana-core packages/core/preboot/core-preboot-server @elastic/kibana-core packages/core/preboot/core-preboot-server-internal @elastic/kibana-core packages/core/preboot/core-preboot-server-mocks @elastic/kibana-core diff --git a/.gitignore b/.gitignore index 82a13e661a5bb..81b0d437f8126 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,12 @@ npm-debug.log* ## @cypress/snapshot from apm plugin /snapshots.js +# transpiled cypress config +x-pack/plugins/fleet/cypress.config.d.ts +x-pack/plugins/fleet/cypress.config.js +x-pack/plugins/osquery/cypress.config.d.ts +x-pack/plugins/osquery/cypress.config.js + # release notes script output report.csv report.asciidoc diff --git a/api_docs/actions.devdocs.json b/api_docs/actions.devdocs.json index 0f63f83fedf12..278caf26266e3 100644 --- a/api_docs/actions.devdocs.json +++ b/api_docs/actions.devdocs.json @@ -772,6 +772,102 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient", + "type": "Class", + "tags": [], + "label": "UnsecuredActionsClient", + "description": [], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "UnsecuredActionsClientOpts" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient.bulkEnqueueExecution", + "type": "Function", + "tags": [], + "label": "bulkEnqueueExecution", + "description": [], + "signature": [ + "(requesterId: string, actionsToExecute: ", + "ExecuteOptions", + "[]) => Promise" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient.bulkEnqueueExecution.$1", + "type": "string", + "tags": [], + "label": "requesterId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "actions", + "id": "def-server.UnsecuredActionsClient.bulkEnqueueExecution.$2", + "type": "Array", + "tags": [], + "label": "actionsToExecute", + "description": [], + "signature": [ + "ExecuteOptions", + "[]" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false } ], "functions": [ @@ -1494,6 +1590,70 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "actions", + "id": "def-server.IUnsecuredActionsClient", + "type": "Interface", + "tags": [], + "label": "IUnsecuredActionsClient", + "description": [], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.IUnsecuredActionsClient.bulkEnqueueExecution", + "type": "Function", + "tags": [], + "label": "bulkEnqueueExecution", + "description": [], + "signature": [ + "(requesterId: string, actionsToExecute: ", + "ExecuteOptions", + "[]) => Promise" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.IUnsecuredActionsClient.bulkEnqueueExecution.$1", + "type": "string", + "tags": [], + "label": "requesterId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "actions", + "id": "def-server.IUnsecuredActionsClient.bulkEnqueueExecution.$2", + "type": "Array", + "tags": [], + "label": "actionsToExecute", + "description": [], + "signature": [ + "ExecuteOptions", + "[]" + ], + "path": "x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "actions", "id": "def-server.PreConfiguredAction", @@ -2240,6 +2400,29 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "actions", + "id": "def-server.PluginStartContract.getUnsecuredActionsClient", + "type": "Function", + "tags": [], + "label": "getUnsecuredActionsClient", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "actions", + "scope": "server", + "docId": "kibActionsPluginApi", + "section": "def-server.IUnsecuredActionsClient", + "text": "IUnsecuredActionsClient" + } + ], + "path": "x-pack/plugins/actions/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "actions", "id": "def-server.PluginStartContract.renderActionParameterTemplates", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 6d674fb6c9a18..97fa8a58713eb 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Response Ops](https://github.com/orgs/elastic/teams/response-ops) for q | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 214 | 0 | 209 | 23 | +| 225 | 0 | 220 | 24 | ## Client diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 736446febbc86..f4a0edb8fdad4 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2022-10-25 +date: 2022-10-27 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 305d1be9b785c..8e2dc536c4852 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 3178e4112dea5..56a1f7d4b752d 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -2848,7 +2848,11 @@ "GetGlobalExecutionKPIParams", ") => Promise<{ success: number; unknown: number; failure: number; warning: number; activeAlerts: number; newAlerts: number; recoveredAlerts: number; erroredActions: number; triggeredActions: number; }>; getRuleExecutionKPI: ({ id, dateStart, dateEnd, filter }: ", "GetRuleExecutionKPIParams", - ") => Promise<{ success: number; unknown: number; failure: number; warning: number; activeAlerts: number; newAlerts: number; recoveredAlerts: number; erroredActions: number; triggeredActions: number; }>; bulkEdit: Promise<{ success: number; unknown: number; failure: number; warning: number; activeAlerts: number; newAlerts: number; recoveredAlerts: number; erroredActions: number; triggeredActions: number; }>; bulkDeleteRules: (options: ", + "BulkDeleteOptions", + ") => Promise<{ errors: ", + "BulkDeleteError", + "[]; total: number; taskIdsFailedToBeDeleted: string[]; }>; bulkEdit: " ], "path": "x-pack/plugins/apm/server/plugin.ts", @@ -183,13 +171,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "APMPluginStartDependencies", ", unknown>, plugins: ", @@ -220,13 +202,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "APMPluginStartDependencies", ", unknown>" @@ -263,13 +239,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ") => void" ], "path": "x-pack/plugins/apm/server/plugin.ts", @@ -284,13 +254,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "x-pack/plugins/apm/server/plugin.ts", "deprecated": false, @@ -753,7 +717,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/sorted_and_filtered_services\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service_groups/services_count\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"POST /internal/apm/correlations/field_stats/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/sorted_and_filtered_services\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service_groups/services_count\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"POST /internal/apm/correlations/field_stats/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\"" ], "path": "x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -1027,6 +991,76 @@ "SpanLinkDetails", "[]; }, ", "APMRouteCreateOptions", + ">; \"GET /internal/apm/storage_explorer/get_services\": ", + "ServerRoute", + "<\"GET /internal/apm/storage_explorer/get_services\", ", + "TypeC", + "<{ query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ indexLifecyclePhase: ", + "UnionC", + "<[", + "LiteralC", + "<", + "IndexLifecyclePhaseSelectOption", + ".All>, ", + "LiteralC", + "<", + "IndexLifecyclePhaseSelectOption", + ".Hot>, ", + "LiteralC", + "<", + "IndexLifecyclePhaseSelectOption", + ".Warm>, ", + "LiteralC", + "<", + "IndexLifecyclePhaseSelectOption", + ".Cold>, ", + "LiteralC", + "<", + "IndexLifecyclePhaseSelectOption", + ".Frozen>]>; }>, ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + "NonEmptyStringBrand", + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>]>; }>, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { services: { serviceName: string; }[]; }, ", + "APMRouteCreateOptions", + ">; \"GET /internal/apm/storage_explorer/is_cross_cluster_search\": ", + "ServerRoute", + "<\"GET /internal/apm/storage_explorer/is_cross_cluster_search\", undefined, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { isCrossClusterSearch: boolean; }, ", + "APMRouteCreateOptions", ">; \"GET /internal/apm/storage_explorer_summary_stats\": ", "ServerRoute", "<\"GET /internal/apm/storage_explorer_summary_stats\", ", @@ -1093,7 +1127,7 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { tracesPerMinute: number; numberOfServices: number; estimatedSize: number; dailyDataGeneration: number; }, ", + ", { tracesPerMinute: number; numberOfServices: number; totalSize: number; diskSpaceUsedPct: number; estimatedIncrementalSize: number; dailyDataGeneration: number; }, ", "APMRouteCreateOptions", ">; \"GET /internal/apm/storage_explorer/privileges\": ", "ServerRoute", @@ -1253,7 +1287,7 @@ "section": "def-common.ProcessorEvent", "text": "ProcessorEvent" }, - "; docs: number; size: number; }[]; }, ", + "; docs: number; size: number; }[]; indicesStats: { indexName: string; numberOfDocs: number; primary?: string | number | undefined; replica?: string | number | undefined; size?: number | undefined; dataStream?: string | undefined; lifecyclePhase?: string | undefined; }[]; }, ", "APMRouteCreateOptions", ">; \"GET /internal/apm/storage_explorer\": ", "ServerRoute", @@ -5003,6 +5037,210 @@ }, ", { serviceCount: number; transactionPerMinute: { value: undefined; timeseries: never[]; } | { value: number; timeseries: { x: number; y: number | null; }[]; }; }, ", "APMRouteCreateOptions", + ">; \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\": ", + "ServerRoute", + "<\"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + "NonEmptyStringBrand", + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ serverlessId: ", + "StringC", + "; }>]>; }>, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { activeInstances: ", + "ActiveInstanceOverview", + "[]; timeseries: ", + "Coordinate", + "[]; }, ", + "APMRouteCreateOptions", + ">; \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\": ", + "ServerRoute", + "<\"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + "NonEmptyStringBrand", + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>]>; }>, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { serverlessFunctionsOverview: { serverlessId: string; serverlessFunctionName: string; serverlessDurationAvg: number | null; billedDurationAvg: number | null; coldStartCount: number | null; avgMemoryUsed: number | undefined; memorySize: number | null; }[]; }, ", + "APMRouteCreateOptions", + ">; \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\": ", + "ServerRoute", + "<\"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + "NonEmptyStringBrand", + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ serverlessId: ", + "StringC", + "; }>]>; }>, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { memoryUsageAvgRate: number | undefined; serverlessFunctionsTotal: number | undefined; serverlessDurationAvg: number | null | undefined; billedDurationAvg: number | null | undefined; }, ", + "APMRouteCreateOptions", + ">; \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\": ", + "ServerRoute", + "<\"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + "NonEmptyStringBrand", + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ serverlessId: ", + "StringC", + "; }>]>; }>, ", + { + "pluginId": "apm", + "scope": "server", + "docId": "kibApmPluginApi", + "section": "def-server.APMRouteHandlerResources", + "text": "APMRouteHandlerResources" + }, + ", { charts: [", + "FetchAndTransformMetrics", + ", ", + "FetchAndTransformMetrics", + ", { series: { overallValue: number; data: { x: number; y: number | null | undefined; }[]; title: string; key: string; type: ", + "ChartType", + "; color: string; }[]; title: string; key: string; yUnit: ", + "YUnit", + "; description?: string | undefined; }, ", + "FetchAndTransformMetrics", + ", ", + "FetchAndTransformMetrics", + "]; }, ", + "APMRouteCreateOptions", ">; \"GET /internal/apm/services/{serviceName}/metrics/nodes\": ", "ServerRoute", "<\"GET /internal/apm/services/{serviceName}/metrics/nodes\", ", @@ -5065,8 +5303,6 @@ "PartialC", "<{ serviceNodeName: ", "StringC", - "; serviceRuntimeName: ", - "StringC", "; }>, ", "TypeC", "<{ environment: ", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index e7f9aa960cfc5..e22939b28442c 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; @@ -21,7 +21,7 @@ Contact [APM UI](https://github.com/orgs/elastic/teams/apm-ui) for questions reg | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 38 | 0 | 38 | 53 | +| 38 | 0 | 38 | 56 | ## Client diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index f74799a487c2e..f16f3cf9d25eb 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2022-10-25 +date: 2022-10-27 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 f120df41c1920..25221b9f93372 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2022-10-25 +date: 2022-10-27 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 faafb543217a9..f54c7efaa9edf 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2022-10-25 +date: 2022-10-27 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 7472ea541f9cd..9645e8dcf1d0a 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2022-10-25 +date: 2022-10-27 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 fac967851e6f1..5631dbdeca13b 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2022-10-25 +date: 2022-10-27 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 ab73aa422cedc..5b2a574909627 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2022-10-25 +date: 2022-10-27 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 70fca17ae4652..e1909e7a093af 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 118948e4ac2e5..1c78ae2cbf9ef 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: 2022-10-25 +date: 2022-10-27 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 e657dd9a0d3ab..281cebcabf59e 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2022-10-25 +date: 2022-10-27 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 1451a0d26b087..7a9eaac825214 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.devdocs.json b/api_docs/controls.devdocs.json index 18be82ecd4f7c..09686e7655b5b 100644 --- a/api_docs/controls.devdocs.json +++ b/api_docs/controls.devdocs.json @@ -3739,6 +3739,34 @@ "path": "src/plugins/controls/common/options_list/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.OptionsListEmbeddableInput.hideExclude", + "type": "CompoundType", + "tags": [], + "label": "hideExclude", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/controls/common/options_list/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.OptionsListEmbeddableInput.exclude", + "type": "CompoundType", + "tags": [], + "label": "exclude", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/controls/common/options_list/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4838,6 +4866,34 @@ "path": "src/plugins/controls/common/options_list/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-common.OptionsListEmbeddableInput.hideExclude", + "type": "CompoundType", + "tags": [], + "label": "hideExclude", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/controls/common/options_list/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-common.OptionsListEmbeddableInput.exclude", + "type": "CompoundType", + "tags": [], + "label": "exclude", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/controls/common/options_list/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 9b4e242923076..d3472eb71af70 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-prese | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 229 | 0 | 220 | 7 | +| 233 | 0 | 224 | 7 | ## Client diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index a84a901314a3f..34c162ad5a2a1 100644 --- a/api_docs/core.devdocs.json +++ b/api_docs/core.devdocs.json @@ -548,6 +548,10 @@ "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, { "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" @@ -588,6 +592,30 @@ "plugin": "@kbn/core-analytics-server-internal", "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, { "plugin": "@kbn/core-root-browser-internal", "path": "packages/core/root/core-root-browser-internal/src/core_system.ts" @@ -684,6 +712,14 @@ "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, { "plugin": "@kbn/core-analytics-server-internal", "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" @@ -922,6 +958,10 @@ "plugin": "telemetry", "path": "src/plugins/telemetry/server/plugin.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, { "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" @@ -978,6 +1018,22 @@ "plugin": "@kbn/core-execution-context-browser-internal", "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, { "plugin": "@kbn/core-status-server-internal", "path": "packages/core/status/core-status-server-internal/src/status_service.ts" @@ -1076,19 +1132,19 @@ }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-server-internal", @@ -4138,6 +4194,64 @@ ], "returnComment": [] }, + { + "parentPluginId": "core", + "id": "def-public.ChromeStart.getGlobalHelpExtensionMenuLinks$", + "type": "Function", + "tags": [], + "label": "getGlobalHelpExtensionMenuLinks$", + "description": [ + "\nGet the list of the registered global help extension menu links" + ], + "signature": [ + "() => ", + "Observable", + "<", + "ChromeGlobalHelpExtensionMenuLink", + "[]>" + ], + "path": "node_modules/@types/kbn__core-chrome-browser/index.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-public.ChromeStart.registerGlobalHelpExtensionMenuLink", + "type": "Function", + "tags": [], + "label": "registerGlobalHelpExtensionMenuLink", + "description": [ + "\nAppend a global help extension menu link" + ], + "signature": [ + "(globalHelpExtensionMenuLink: ", + "ChromeGlobalHelpExtensionMenuLink", + ") => void" + ], + "path": "node_modules/@types/kbn__core-chrome-browser/index.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-public.ChromeStart.registerGlobalHelpExtensionMenuLink.$1", + "type": "Object", + "tags": [], + "label": "globalHelpExtensionMenuLink", + "description": [], + "signature": [ + "ChromeGlobalHelpExtensionMenuLink" + ], + "path": "node_modules/@types/kbn__core-chrome-browser/index.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "core", "id": "def-public.ChromeStart.getHelpExtension$", @@ -4145,7 +4259,7 @@ "tags": [], "label": "getHelpExtension$", "description": [ - "\nGet an observable of the current custom help conttent" + "\nGet an observable of the current custom help content" ], "signature": [ "() => ", @@ -19349,6 +19463,10 @@ "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, { "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" @@ -19389,6 +19507,30 @@ "plugin": "@kbn/core-analytics-server-internal", "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, { "plugin": "@kbn/core-root-browser-internal", "path": "packages/core/root/core-root-browser-internal/src/core_system.ts" @@ -19485,6 +19627,14 @@ "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, { "plugin": "@kbn/core-analytics-server-internal", "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" @@ -19723,6 +19873,10 @@ "plugin": "telemetry", "path": "src/plugins/telemetry/server/plugin.ts" }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, { "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" @@ -19779,6 +19933,22 @@ "plugin": "@kbn/core-execution-context-browser-internal", "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, { "plugin": "@kbn/core-status-server-internal", "path": "packages/core/status/core-status-server-internal/src/status_service.ts" @@ -19877,19 +20047,19 @@ }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-browser-internal", - "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" }, { "plugin": "@kbn/core-analytics-server-internal", @@ -20107,20 +20277,23 @@ "\nA plugin with asynchronous lifecycle methods.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.AsyncPlugin", - "text": "AsyncPlugin" - }, + "AsyncPlugin", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": true, "removeBy": "8.8.0", "trackAdoption": false, - "references": [], + "references": [ + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin.ts" + } + ], "children": [ { "parentPluginId": "core", @@ -20131,16 +20304,10 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", plugins: TPluginsSetup) => TSetup | Promise" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -20152,16 +20319,10 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -20176,7 +20337,7 @@ "signature": [ "TPluginsSetup" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -20193,16 +20354,10 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", plugins: TPluginsStart) => TStart | Promise" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -20214,15 +20369,9 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -20237,7 +20386,7 @@ "signature": [ "TPluginsStart" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -20255,7 +20404,7 @@ "signature": [ "(() => void) | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -21544,7 +21693,10 @@ "description": [ "\nContext passed to the `setup` method of `preboot` plugins." ], - "path": "src/core/server/index.ts", + "signature": [ + "CorePreboot" + ], + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -21576,7 +21728,7 @@ "ContextProviderOpts", ") => void; removeContextProvider: (contextProviderName: string) => void; }" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21592,7 +21744,7 @@ "signature": [ "ElasticsearchServicePreboot" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21611,7 +21763,7 @@ "RequestHandlerContext", ">" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21627,7 +21779,7 @@ "signature": [ "PrebootServicePreboot" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -21752,16 +21904,10 @@ "\nContext passed to the `setup` method of `standard` plugins.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -21793,7 +21939,7 @@ "ContextProviderOpts", ") => void; removeContextProvider: (contextProviderName: string) => void; }" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21809,7 +21955,7 @@ "signature": [ "CapabilitiesSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21825,7 +21971,7 @@ "signature": [ "DocLinksServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21841,7 +21987,7 @@ "signature": [ "ElasticsearchServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21857,7 +22003,7 @@ "signature": [ "ExecutionContextSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21878,7 +22024,7 @@ "HttpResources", "; }" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21894,7 +22040,7 @@ "signature": [ "I18nServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21910,7 +22056,7 @@ "signature": [ "LoggingServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21926,7 +22072,7 @@ "signature": [ "MetricsServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21942,7 +22088,7 @@ "signature": [ "SavedObjectsServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21958,7 +22104,7 @@ "signature": [ "StatusServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21974,7 +22120,7 @@ "signature": [ "UiSettingsServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -21990,7 +22136,7 @@ "signature": [ "DeprecationsServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22005,16 +22151,10 @@ ], "signature": [ "() => Promise<[", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", TPluginsStart, TStart]>" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -22032,7 +22172,10 @@ "description": [ "\nContext passed to the plugins `start` method.\n" ], - "path": "src/core/server/index.ts", + "signature": [ + "CoreStart" + ], + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -22054,7 +22197,7 @@ "TelemetryCounter", ">; }" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22070,7 +22213,7 @@ "signature": [ "CapabilitiesStart" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22086,7 +22229,7 @@ "signature": [ "DocLinksServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22102,7 +22245,7 @@ "signature": [ "ElasticsearchServiceStart" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22118,7 +22261,7 @@ "signature": [ "ExecutionContextSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22134,7 +22277,7 @@ "signature": [ "HttpServiceStart" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22150,7 +22293,7 @@ "signature": [ "MetricsServiceSetup" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22166,7 +22309,7 @@ "signature": [ "SavedObjectsServiceStart" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -22182,7 +22325,7 @@ "signature": [ "UiSettingsServiceStart" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -25223,6 +25366,14 @@ "plugin": "@kbn/core-elasticsearch-server-internal", "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.ts" }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, { "plugin": "@kbn/core-elasticsearch-server-internal", "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts" @@ -37592,16 +37743,10 @@ "\nThe interface that should be returned by a `PluginInitializer` for a `standard` plugin.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37614,16 +37759,10 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", plugins: TPluginsSetup) => TSetup" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37635,16 +37774,10 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -37659,7 +37792,7 @@ "signature": [ "TPluginsSetup" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -37676,16 +37809,10 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", plugins: TPluginsStart) => TStart" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37697,15 +37824,9 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -37720,7 +37841,7 @@ "signature": [ "TPluginsStart" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -37738,7 +37859,7 @@ "signature": [ "(() => void) | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -37757,16 +37878,10 @@ "\nDescribes a plugin configuration properties.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginConfigDescriptor", - "text": "PluginConfigDescriptor" - }, + "PluginConfigDescriptor", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37783,7 +37898,7 @@ "ConfigDeprecationProvider", " | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37797,16 +37912,10 @@ "\nList of configuration properties that will be available on the client-side plugin." ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.ExposedToBrowserDescriptor", - "text": "ExposedToBrowserDescriptor" - }, + "ExposedToBrowserDescriptor", " | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37823,7 +37932,7 @@ "Type", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37837,16 +37946,10 @@ "\nExpose non-default configs to usage collection to be sent via telemetry.\nset a config to `true` to report the actual changed config value.\nset a config to `false` to report the changed config value as [redacted].\n\nAll changed configs except booleans and numbers will be reported\nas [redacted] unless otherwise specified.\n\n{@link MakeUsageFromSchema}" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.MakeUsageFromSchema", - "text": "MakeUsageFromSchema" - }, + "MakeUsageFromSchema", " | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -37863,16 +37966,10 @@ "\nContext that's available to plugins during initialization stage.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37886,7 +37983,7 @@ "signature": [ "symbol" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37904,7 +38001,7 @@ "PackageInfo", ">; instanceUuid: string; configs: readonly string[]; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37920,7 +38017,7 @@ "signature": [ "NodeInfo" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37936,7 +38033,7 @@ "signature": [ "LoggerFactory" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -37968,7 +38065,7 @@ "Observable", "; get: () => T; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -37984,7 +38081,10 @@ "description": [ "\nDescribes the set of required and optional properties plugin can define in its\nmandatory JSON manifest file.\n" ], - "path": "src/core/server/plugins/types.ts", + "signature": [ + "PluginManifest" + ], + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -37997,7 +38097,7 @@ "description": [ "\nIdentifier of the plugin. Must be a string in camelCase. Part of a plugin public contract.\nOther plugins leverage it to access plugin API, navigate to the plugin, etc." ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38010,7 +38110,7 @@ "description": [ "\nVersion of the plugin." ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38023,7 +38123,7 @@ "description": [ "\nThe version of Kibana the plugin is compatible with, defaults to \"version\"." ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38039,7 +38139,7 @@ "signature": [ "PluginType" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38055,7 +38155,7 @@ "signature": [ "string | string[]" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38071,7 +38171,7 @@ "signature": [ "readonly string[]" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38087,7 +38187,7 @@ "signature": [ "readonly string[]" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38103,7 +38203,7 @@ "signature": [ "readonly string[]" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38116,7 +38216,7 @@ "description": [ "\nSpecifies whether plugin includes some client/browser specific functionality\nthat should be included into client bundle via `public/ui_plugin.js` file." ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38129,7 +38229,7 @@ "description": [ "\nSpecifies whether plugin includes some server-side specific functionality." ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38147,10 +38247,35 @@ "signature": [ "string[] | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": true, "trackAdoption": false, - "references": [] + "references": [ + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts" + } + ] }, { "parentPluginId": "core", @@ -38164,7 +38289,7 @@ "signature": [ "readonly string[] | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38178,7 +38303,7 @@ "signature": [ "{ readonly name: string; readonly githubTeam?: string | undefined; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38194,7 +38319,7 @@ "signature": [ "string | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false }, @@ -38210,7 +38335,7 @@ "signature": [ "boolean | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -39522,16 +39647,10 @@ "\nThe interface that should be returned by a `PluginInitializer` for a `preboot` plugin.\n" ], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PrebootPlugin", - "text": "PrebootPlugin" - }, + "PrebootPlugin", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -39544,16 +39663,10 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CorePreboot", - "text": "CorePreboot" - }, + "CorePreboot", ", plugins: TPluginsSetup) => TSetup" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -39565,15 +39678,9 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CorePreboot", - "text": "CorePreboot" - } + "CorePreboot" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -39588,7 +39695,7 @@ "signature": [ "TPluginsSetup" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -39606,7 +39713,7 @@ "signature": [ "(() => void) | undefined" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -51818,17 +51925,15 @@ "\nType defining the list of configuration properties that will be exposed on the client-side\nObject properties can either be fully exposed\n" ], "signature": [ - "{ [Key in keyof T]?: (T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.ExposedToBrowserDescriptor", - "text": "ExposedToBrowserDescriptor" - }, + "{ [Key in keyof T]?: (T[Key] extends ", + "Maybe", + " ? boolean : T[Key] extends ", + "Maybe", + " ? boolean | ", + "ExposedToBrowserDescriptor", " : boolean) | undefined; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -52475,17 +52580,17 @@ "\nList of configuration values that will be exposed to usage collection.\nIf parent node or actual config path is set to `true` then the actual value\nof these configs will be reoprted.\nIf parent node or actual config path is set to `false` then the config\nwill be reported as [redacted].\n" ], "signature": [ - "{ [Key in keyof T]?: (T[Key] extends Maybe ? false : T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.MakeUsageFromSchema", - "text": "MakeUsageFromSchema" - }, + "{ [Key in keyof T]?: (T[Key] extends ", + "Maybe", + " ? false : T[Key] extends ", + "Maybe", + " ? boolean : T[Key] extends ", + "Maybe", + " ? boolean | ", + "MakeUsageFromSchema", " : boolean) | undefined; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -52847,7 +52952,7 @@ "Type", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -52863,40 +52968,16 @@ ], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", ") => ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", " | ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PrebootPlugin", - "text": "PrebootPlugin" - }, + "PrebootPlugin", " | ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.AsyncPlugin", - "text": "AsyncPlugin" - }, + "AsyncPlugin", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -52909,16 +52990,10 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -54143,7 +54218,7 @@ "ByteSizeValue", ") => boolean; getValueInBytes: () => number; toString: (returnUnit?: ByteSizeValueUnit | undefined) => string; }>; }>; }" ], - "path": "src/core/server/plugins/types.ts", + "path": "node_modules/@types/kbn__core-plugins-server/index.d.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -54159,16 +54234,10 @@ ], "signature": [ "() => Promise<[", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", TPluginsStart, TStart]>" ], - "path": "src/core/server/index.ts", + "path": "node_modules/@types/kbn__core-lifecycle-server/index.d.ts", "deprecated": false, "trackAdoption": false, "returnComment": [], diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 02dac22253f60..b8b5be21f4bde 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2697 | 0 | 23 | 0 | +| 2700 | 0 | 0 | 0 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index e459ca347f57e..217bdbe22a03a 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2022-10-25 +date: 2022-10-27 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 16f47378912af..5ca3a0a085c1d 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2022-10-25 +date: 2022-10-27 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 ed6cf316f367b..4b7e08de75b38 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 5b1041ce4f855..adb716ba2c9e8 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -11752,13 +11752,7 @@ "text": "DataServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "data", @@ -11807,13 +11801,7 @@ "label": "initializerContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" ], "path": "src/plugins/data/server/plugin.ts", @@ -11833,13 +11821,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "DataPluginStartDependencies", ", ", @@ -11878,13 +11860,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "DataPluginStartDependencies", ", ", @@ -11929,13 +11905,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", { fieldFormats, dataViews, taskManager }: ", "DataPluginStartDependencies", ") => { datatableUtilities: ", @@ -11988,13 +11958,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/data/server/plugin.ts", "deprecated": false, diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 58ce710450668..6a152f1c66866 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2022-10-25 +date: 2022-10-27 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 dad41749303b4..4c8e53d0ef0fe 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 9aa18ac220570..f14a2145fda16 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -1519,13 +1519,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", deps: SetupDependencies) => void" ], "path": "src/plugins/data/server/search/session/session_service.ts", @@ -1540,13 +1534,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], "path": "src/plugins/data/server/search/session/session_service.ts", @@ -1581,13 +1569,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", deps: StartDependencies) => void" ], "path": "src/plugins/data/server/search/session/session_service.ts", @@ -1602,13 +1584,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -2516,13 +2492,7 @@ "description": [], "signature": [ "({ savedObjects, elasticsearch }: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ") => (request: ", "KibanaRequest", ") => { getId: (args_0: ", @@ -2655,13 +2625,7 @@ "label": "{ savedObjects, elasticsearch }", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -3160,13 +3124,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ") => (request: ", "KibanaRequest", ") => ", @@ -3184,13 +3142,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/data/server/search/session/types.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index aac967b04b83a..bfd955dd39f9f 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2022-10-25 +date: 2022-10-27 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 f7df206f7f231..9a4dd2a78efcc 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2022-10-25 +date: 2022-10-27 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 9a7678522e99a..22b10e0018364 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2022-10-25 +date: 2022-10-27 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 4b0c4c2c59d23..cbb9a1b524b4e 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index e66691e1282d6..5566ad1bdd962 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -10471,13 +10471,7 @@ "text": "DataViewsServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "dataViews", @@ -10538,13 +10532,7 @@ "label": "initializerContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], "path": "src/plugins/data_views/server/plugin.ts", @@ -10564,13 +10552,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", { "pluginId": "dataViews", @@ -10609,13 +10591,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", { "pluginId": "dataViews", @@ -10672,13 +10648,7 @@ "description": [], "signature": [ "({ uiSettings, capabilities }: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", { fieldFormats }: ", { "pluginId": "dataViews", @@ -10715,13 +10685,7 @@ "label": "{ uiSettings, capabilities }", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/data_views/server/plugin.ts", "deprecated": false, diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 0b70882fda9a5..b4766e2d9885c 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2022-10-25 +date: 2022-10-27 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 dd0bef405d5dd..8a268d23ca716 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2022-10-25 +date: 2022-10-27 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 36437e5539be4..019e1115caa97 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -69,7 +69,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | dataViewManagement | - | | | dataViewManagement | - | | | enterpriseSearch | - | -| | console, @kbn/core-elasticsearch-server-internal | - | +| | console, @kbn/core-elasticsearch-server-internal, @kbn/core-plugins-server-internal | - | +| | @kbn/core-plugins-server-internal | - | | | spaces, security, alerting | 8.8.0 | | | spaces, security, actions, alerting, ml, remoteClusters, graph, indexLifecycleManagement, mapsEms, painlessLab, rollup, searchprofiler, securitySolution, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | embeddable, discover, presentationUtil, dashboard, graph | 8.8.0 | @@ -88,6 +89,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | apm | 8.8.0 | | | security | 8.8.0 | | | mapsEms | 8.8.0 | +| | @kbn/core-plugins-server-internal | 8.8.0 | | | ml, @kbn/core-http-browser-internal | 8.8.0 Note to maintainers: when looking at usages, mind that typical use could be inside a `catch` block, @@ -142,8 +144,6 @@ Safe to remove. | | reporting | | | reporting | | | taskManager | -| | core | -| | core | | | @kbn/storybook | | | @kbn/core-application-browser | | | @kbn/core-application-browser | @@ -154,6 +154,8 @@ Safe to remove. | | @kbn/core-injected-metadata-browser | | | @kbn/core-injected-metadata-browser | | | @kbn/core-metrics-server | +| | @kbn/core-plugins-server | +| | @kbn/core-plugins-server | | | @kbn/core-saved-objects-common | | | @kbn/core-saved-objects-common | | | @kbn/core-saved-objects-server | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index d741999d51363..a0c2c750783b4 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -70,6 +70,16 @@ so TS and code-reference navigation might not highlight them. | +## @kbn/core-plugins-server-internal + +| Deprecated API | Reference location(s) | Remove By | +| ---------------|-----------|-----------| +| | [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=legacy), [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=legacy) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin), [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin) | 8.8.0 | +| | [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs) | - | + + + ## @kbn/core-saved-objects-migration-server-internal | Deprecated API | Reference location(s) | Remove By | @@ -715,13 +725,13 @@ so TS and code-reference navigation might not highlight them. | | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | | | [disable_ui_capabilities.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts#:~:text=requiredRoles) | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | -| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | -| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | | | [disable_ui_capabilities.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts#:~:text=requiredRoles) | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 1acb6bf498874..5b3583ec8c17d 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -78,6 +78,7 @@ so TS and code-reference navigation might not highlight them. | Note to maintainers: when looking at usages, mind that typical use could be inside a `catch` block, so TS and code-reference navigation might not highlight them. | +| @kbn/core-plugins-server-internal | | [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin), [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin) | 8.8.0 | | @kbn/core-saved-objects-migration-server-internal | | [document_migrator.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/document_migrator.test.ts#:~:text=warning), [migration_logger.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/migration_logger.ts#:~:text=warning) | 8.8.0 | | @kbn/core-apps-browser-internal | | [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts#:~:text=process), [load_status.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.test.ts#:~:text=process), [ops_metrics_collector.ts](https://github.com/elastic/kibana/tree/main/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.ts#:~:text=process), [get_ops_metrics_log.ts](https://github.com/elastic/kibana/tree/main/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.ts#:~:text=process), [get_ops_metrics_log.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.test.ts#:~:text=process)+ 5 more | 8.8.0 | @@ -130,13 +131,13 @@ so TS and code-reference navigation might not highlight them. | | --------|-------|-----------|-----------| | spaces | | [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures), [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 18 more | 8.8.0 | | spaces | | [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [spaces_usage_collector.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.test.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/plugin.ts#:~:text=license%24) | 8.8.0 | -| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | | security | | [disable_ui_capabilities.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts#:~:text=requiredRoles) | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | -| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | -| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | +| security | | [elasticsearch_role.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [role_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/lib/role_utils.ts#:~:text=disabled), [primary_feature_privilege.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts#:~:text=disabled), [elasticsearch_role.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.test.ts#:~:text=disabled), [kibana_features.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts#:~:text=disabled), [put.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled), [put_payload.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts#:~:text=disabled) | 8.8.0 | | security | | [disable_ui_capabilities.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts#:~:text=requiredRoles) | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 38245384d2d9d..45bf1b3ead4e5 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2022-10-25 +date: 2022-10-27 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 da039fd0aa0e6..e937879b1ca45 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2022-10-25 +date: 2022-10-27 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 8da680c5e9871..ab8066ed2c8e2 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index f26eb0f78e6dd..ef416f5b3c1ee 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2022-10-25 +date: 2022-10-27 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 ae973890d6970..9d529653959bc 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2022-10-25 +date: 2022-10-27 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 11f51b7d54aed..dcf224a87f820 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index fdbb8cdaa8ed7..6affa8cf4a397 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2022-10-25 +date: 2022-10-27 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 36c4e9e40163f..099d8c9d85382 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 931b4be683eae..726d0b7f09340 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2022-10-25 +date: 2022-10-27 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 8198f4414a455..2a6fa718a80ee 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 8df865e80d5f2..e7a98f24768c0 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2022-10-25 +date: 2022-10-27 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 3fa2e68cd897b..dbe7df0dfc637 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2022-10-25 +date: 2022-10-27 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 e3f5eb4750b51..0d45f8b3f48dc 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2022-10-25 +date: 2022-10-27 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 60b93f5bf1254..abcff3f3c350a 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2022-10-25 +date: 2022-10-27 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 bf161b0e552b0..a2b9798a1b2f4 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2022-10-25 +date: 2022-10-27 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 75fab4a1e4ff3..22901ca9906d9 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2022-10-25 +date: 2022-10-27 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 26a880dc63746..19f6b242c922b 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2022-10-25 +date: 2022-10-27 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 15bc59f1a1989..8c19667e6c802 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2022-10-25 +date: 2022-10-27 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 eddb856850910..41aef8c5baa03 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2022-10-25 +date: 2022-10-27 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 f9199358565d6..3f810f773ab8b 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2022-10-25 +date: 2022-10-27 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 b2107badf98ef..99bc6c657949a 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2022-10-25 +date: 2022-10-27 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 585c38b73fa7f..6378f837dd644 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2022-10-25 +date: 2022-10-27 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 904c6304b38a6..7a065b0d41bc5 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index fdfba4c5796c5..8888cbfd994f0 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -16121,13 +16121,7 @@ "text": "ExpressionsServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "expressions", @@ -16192,13 +16186,7 @@ "label": "context", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], "path": "src/plugins/expressions/server/plugin.ts", @@ -16218,13 +16206,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ") => ", { "pluginId": "expressions", @@ -16246,13 +16228,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], "path": "src/plugins/expressions/server/plugin.ts", @@ -16272,13 +16248,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ") => ", { "pluginId": "expressions", @@ -16300,13 +16270,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/expressions/server/plugin.ts", "deprecated": false, diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index d45c4de592f8d..5c07ea40103d3 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.devdocs.json b/api_docs/features.devdocs.json index cbbe75fe20fa4..4214e7c762f0a 100644 --- a/api_docs/features.devdocs.json +++ b/api_docs/features.devdocs.json @@ -56,7 +56,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -372,6 +372,10 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/put.test.ts" }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" + }, { "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" @@ -817,6 +821,38 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "features", + "id": "def-public.SubFeatureConfig.requireAllSpaces", + "type": "CompoundType", + "tags": [], + "label": "requireAllSpaces", + "description": [ + "\nWhether or not this privilege should only be granted to `All Spaces *`. Should be used for features that do not\nsupport Spaces. Defaults to `false`." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/features/common/sub_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-public.SubFeatureConfig.privilegesTooltip", + "type": "string", + "tags": [], + "label": "privilegesTooltip", + "description": [ + "\nOptional message to display on the Role Management screen when configuring permissions for this feature." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/features/common/sub_feature.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "features", "id": "def-public.SubFeatureConfig.privilegeGroups", @@ -1185,7 +1221,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -1680,6 +1716,10 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/put.test.ts" }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" + }, { "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" @@ -2868,7 +2908,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -3118,7 +3158,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ name: string; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -3169,6 +3209,17 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "features", + "id": "def-common.SubFeature.requireAllSpaces", + "type": "boolean", + "tags": [], + "label": "requireAllSpaces", + "description": [], + "path": "x-pack/plugins/features/common/sub_feature.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "features", "id": "def-common.SubFeature.toRaw", @@ -3177,7 +3228,7 @@ "label": "toRaw", "description": [], "signature": [ - "() => { name: string; privilegeGroups: readonly Readonly<{ groupType: ", + "() => { name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -3474,6 +3525,10 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/put.test.ts" }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" + }, { "plugin": "security", "path": "x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts" @@ -3919,6 +3974,38 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "features", + "id": "def-common.SubFeatureConfig.requireAllSpaces", + "type": "CompoundType", + "tags": [], + "label": "requireAllSpaces", + "description": [ + "\nWhether or not this privilege should only be granted to `All Spaces *`. Should be used for features that do not\nsupport Spaces. Defaults to `false`." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/features/common/sub_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-common.SubFeatureConfig.privilegesTooltip", + "type": "string", + "tags": [], + "label": "privilegesTooltip", + "description": [ + "\nOptional message to display on the Role Management screen when configuring permissions for this feature." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/features/common/sub_feature.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "features", "id": "def-common.SubFeatureConfig.privilegeGroups", diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 36a30ac629632..d0d910454e88a 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 222 | 0 | 95 | 2 | +| 227 | 0 | 96 | 2 | ## Client diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 1e32b5a52ee8d..5d5c149caa585 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2022-10-25 +date: 2022-10-27 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 f556da2c06bd3..35d78a391abf5 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.devdocs.json b/api_docs/files.devdocs.json index dcabddd455d1a..7388e47d5ca19 100644 --- a/api_docs/files.devdocs.json +++ b/api_docs/files.devdocs.json @@ -901,24 +901,6 @@ "trackAdoption": false, "children": [], "returnComment": [] - }, - { - "parentPluginId": "files", - "id": "def-public.Props.lazy", - "type": "CompoundType", - "tags": [ - "default" - ], - "label": "lazy", - "description": [ - "\nAs an optimisation images are only loaded when they are visible.\nThis setting overrides this behavior and loads an image as soon as the\ncomponent mounts.\n" - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/files/public/components/image/image.tsx", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 05b84037a1023..a72d27eb13799 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/tea | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 272 | 0 | 18 | 2 | +| 271 | 0 | 18 | 2 | ## Client diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 17fbfc6069a27..a95e99d7f7774 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2022-10-25 +date: 2022-10-27 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 4298e3995a682..c102ddbce9f83 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2022-10-25 +date: 2022-10-27 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 83cd38c62e176..d2f54cde989c0 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: 2022-10-25 +date: 2022-10-27 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 5d8b8f0b78edb..9f8267fbd0bd1 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 204cdf74b1b2c..1f98919bac6b3 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2022-10-25 +date: 2022-10-27 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 2ef045c32473b..e8de84f565030 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2022-10-25 +date: 2022-10-27 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 fa47edf9c37ea..11b21e8dbb6b2 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2022-10-25 +date: 2022-10-27 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 0ccf060216d30..cdb258cc847e0 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2022-10-25 +date: 2022-10-27 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 e9c1c38afe944..abfc607808752 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2022-10-25 +date: 2022-10-27 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 4bcf24806e13e..9847dee0009a6 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2022-10-25 +date: 2022-10-27 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 930763851a05f..f4cc1b14a9826 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2022-10-25 +date: 2022-10-27 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 8a6ae11008635..ca93de01e5337 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 498373b27fc1f..e2af46fb3bcda 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index e612d5e9f2686..7b2d8e07b4bf4 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2022-10-25 +date: 2022-10-27 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 c0939902748df..0f0a36e4824e0 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2022-10-25 +date: 2022-10-27 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 0da232131bd66..d757d13d6feca 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 9e54c4ecc9f24..18c2f4e816e93 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2022-10-25 +date: 2022-10-27 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 f1f68e6e12c9a..b91cea2c602cc 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2022-10-25 +date: 2022-10-27 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 94eaab7649126..34465561f4853 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2022-10-25 +date: 2022-10-27 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 167098286c130..3208aed0747f1 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: 2022-10-25 +date: 2022-10-27 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 221ad0e89d1b0..31e60a33a1c8f 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2022-10-25 +date: 2022-10-27 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 55cd0d93ba713..5d386cd8bf5ba 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 195537336c476..110beeb3cc918 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 3c0f55faa1182..e46c4819f134d 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2022-10-25 +date: 2022-10-27 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 224c0dbbbbd72..ad05a61239ed9 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index d8f469942e50c..40322ae78a1cb 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2022-10-25 +date: 2022-10-27 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 06d0b062db8a4..9a2a46ba869ce 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2022-10-25 +date: 2022-10-27 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 455ffa4b37590..ceedbfc013c95 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2022-10-25 +date: 2022-10-27 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 fd60744b830e9..2f1210d1db411 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2022-10-25 +date: 2022-10-27 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 7dca18a6fe21a..dfdd60e0d6821 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index ae2e9ae19ea50..93a4c258f96e0 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2022-10-25 +date: 2022-10-27 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 f2f3845f6d49a..bfa20abb792ff 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2022-10-25 +date: 2022-10-27 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 cdd0371e93c1f..c1b612cd46ef8 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 71b7600aaebba..e45fb544c8e68 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index 34b7c959f958a..4903301355b2c 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: 2022-10-25 +date: 2022-10-27 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_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index bbab9a9d112e4..130f63eb2329f 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 3234655c413fb..c3fcca0bb1258 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 b31cd3c9d3ed5..9c793c948fe42 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 162c8e6cbfdcf..4603be95b2a58 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2022-10-25 +date: 2022-10-27 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 ccbf96dddc7f3..0ec328a7695d9 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 6259c2591140a..8efb0ba3b45b5 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 1b89ddf0c711c..264acd0128266 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: 2022-10-25 +date: 2022-10-27 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 274075d7f5487..38471bd9b7509 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: 2022-10-25 +date: 2022-10-27 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 c5ec5b29757e5..edd31fd4e8de8 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: 2022-10-25 +date: 2022-10-27 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 41dfc5c057d40..8150b0ad7c64e 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: 2022-10-25 +date: 2022-10-27 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 36edfe6ccecff..c6d522c54582a 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: 2022-10-25 +date: 2022-10-27 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 81cb83586818e..a4b2f7eb46508 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: 2022-10-25 +date: 2022-10-27 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_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index a41603ae3aeca..83c35c9b87678 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 3bd018069c91e..9281a8d054fd3 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2022-10-25 +date: 2022-10-27 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 bec7d0d6b15e2..f1fa0d588eb59 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 ad2b0b4a84cda..af8da8e505f15 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 9f5fb1c9f3129..a964a90f20dfa 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: 2022-10-25 +date: 2022-10-27 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 b439f9c55d08d..34ee6cf57d9ad 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2022-10-25 +date: 2022-10-27 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 4da9c4e3875b8..e45b8ea94cb52 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2022-10-25 +date: 2022-10-27 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 0c58763010fd0..e4438f7d3cea9 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index fb399e5080e6f..ac10e8f1cb1d1 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -187,6 +187,50 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeGlobalHelpExtensionMenuLink", + "type": "Interface", + "tags": [], + "label": "ChromeGlobalHelpExtensionMenuLink", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.ChromeGlobalHelpExtensionMenuLink", + "text": "ChromeGlobalHelpExtensionMenuLink" + }, + " extends ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.ChromeHelpExtensionMenuCustomLink", + "text": "ChromeHelpExtensionMenuCustomLink" + } + ], + "path": "packages/core/chrome/core-chrome-browser/src/help_extension.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeGlobalHelpExtensionMenuLink.priority", + "type": "number", + "tags": [], + "label": "priority", + "description": [ + "\nHighest priority items are listed at the top of the list of links." + ], + "path": "packages/core/chrome/core-chrome-browser/src/help_extension.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.ChromeHelpExtension", @@ -1882,6 +1926,82 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeStart.getGlobalHelpExtensionMenuLinks$", + "type": "Function", + "tags": [], + "label": "getGlobalHelpExtensionMenuLinks$", + "description": [ + "\nGet the list of the registered global help extension menu links" + ], + "signature": [ + "() => ", + "Observable", + "<", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.ChromeGlobalHelpExtensionMenuLink", + "text": "ChromeGlobalHelpExtensionMenuLink" + }, + "[]>" + ], + "path": "packages/core/chrome/core-chrome-browser/src/contracts.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeStart.registerGlobalHelpExtensionMenuLink", + "type": "Function", + "tags": [], + "label": "registerGlobalHelpExtensionMenuLink", + "description": [ + "\nAppend a global help extension menu link" + ], + "signature": [ + "(globalHelpExtensionMenuLink: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.ChromeGlobalHelpExtensionMenuLink", + "text": "ChromeGlobalHelpExtensionMenuLink" + }, + ") => void" + ], + "path": "packages/core/chrome/core-chrome-browser/src/contracts.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeStart.registerGlobalHelpExtensionMenuLink.$1", + "type": "Object", + "tags": [], + "label": "globalHelpExtensionMenuLink", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.ChromeGlobalHelpExtensionMenuLink", + "text": "ChromeGlobalHelpExtensionMenuLink" + } + ], + "path": "packages/core/chrome/core-chrome-browser/src/contracts.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.ChromeStart.getHelpExtension$", @@ -1889,7 +2009,7 @@ "tags": [], "label": "getHelpExtension$", "description": [ - "\nGet an observable of the current custom help conttent" + "\nGet an observable of the current custom help content" ], "signature": [ "() => ", diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 7bdf58691ef6a..2db0226b148d5 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 114 | 0 | 41 | 0 | +| 119 | 0 | 43 | 0 | ## Common diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 877e13fd53568..8879661860eb7 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: 2022-10-25 +date: 2022-10-27 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 2c86c9f09e1c3..2bf7804911206 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 2f6d7e1704309..e72f5003eb85b 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 bc13e2aa40d82..893daa641bc41 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 af385e60f6383..96563e8f54e98 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 e4f5aa2ff2696..c5b48f2ad3ba4 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2022-10-25 +date: 2022-10-27 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 010a4909b6f3e..7e7d21fac0e22 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: 2022-10-25 +date: 2022-10-27 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 8bb8f8513ff04..bea005a7d4e59 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: 2022-10-25 +date: 2022-10-27 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 6c6bf36cd9759..621351457c9b7 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: 2022-10-25 +date: 2022-10-27 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 56815ba6aecf3..5e9c2399d86f7 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 91d5c6d38c2d0..7dd5e0cc196b8 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 7cdbc1ce23553..ce8f26292872b 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2022-10-25 +date: 2022-10-27 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 0ea7db975e3db..a4a47dc9b0598 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 0499573b55bff..82251a0065910 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 cadb71fe47454..e6ba16076c79c 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 ac7303c668aa2..6f1770f9c9235 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2022-10-25 +date: 2022-10-27 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 e4a016ceef1ea..0520f9cd4178c 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 f52013e2a7f4b..3400d697b5e40 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 c34f1f7f0f848..99ac72bc588ed 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 9672d657864ec..d98964ff87f6c 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 ef680a3f3045c..44cb268cc8f87 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 de9e9493bdd22..b137763f0873c 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 9cf3bcaa439e2..a4983dabb70ad 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 959c562c02eb1..8231f970b3f6a 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2022-10-25 +date: 2022-10-27 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 b99b2027b46b6..9417f15d7d4bf 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2022-10-25 +date: 2022-10-27 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 72c5ecd82b4d7..e1ef9bf2b29f2 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 ea82ee20975a2..5e4b9da6d9d2d 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 58c5359e1032e..bd889b07d2448 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 fd247bbeded0a..e0b057a2c9c88 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 f05fb90e3797d..e77c9663bb88f 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 36e0fa773c3f8..d551bfbb4615e 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 04a41071e68a1..a7aa82dee2b5d 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 b64dfba67a50b..adff4618167ec 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2022-10-25 +date: 2022-10-27 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 5c149b02fd618..1ffcaeca27d27 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 cff4933ab544e..2b3c79c28cd22 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: 2022-10-25 +date: 2022-10-27 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 311adf9c79872..a9d46143fe6c0 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: 2022-10-25 +date: 2022-10-27 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 737fc39ad50ac..c34e11e1431bc 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: 2022-10-25 +date: 2022-10-27 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 62dc0ab9ab148..860aa126a5781 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: 2022-10-25 +date: 2022-10-27 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 f805622642026..39eac9e75b745 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 bd5a34cd3906f..49698d0b41fbb 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 99f868cb457cf..418d2b36dfd4b 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2022-10-25 +date: 2022-10-27 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 18bf384a95ac1..8c4e8dcbecf2a 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 c79757fdbe987..bcd232b3dedf8 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 7e0e711a696b3..ba6a0d53685ae 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 ddd88228d0261..1d8acfda2155a 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 b927a0dcd9e9c..006c15a3fbc7c 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: 2022-10-25 +date: 2022-10-27 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 9b8efb08b0089..1e150ac8f8e60 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: 2022-10-25 +date: 2022-10-27 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 51d5f464d4238..be156b5dfd52d 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: 2022-10-25 +date: 2022-10-27 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.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index c8f3f7f8ccbbb..f0948fd647d0b 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 2a72210a9f78a..9924c35a59a11 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 b29c40831215c..6e805256d4a71 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 e49e6da514326..9170729fab145 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index a583e80285fe9..2ec34fc78d756 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: 2022-10-25 +date: 2022-10-27 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 b70219d28445c..572a23b692621 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: 2022-10-25 +date: 2022-10-27 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.devdocs.json b/api_docs/kbn_core_lifecycle_server.devdocs.json new file mode 100644 index 0000000000000..c49e0d2cda602 --- /dev/null +++ b/api_docs/kbn_core_lifecycle_server.devdocs.json @@ -0,0 +1,602 @@ +{ + "id": "@kbn/core-lifecycle-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CorePreboot", + "type": "Interface", + "tags": [], + "label": "CorePreboot", + "description": [ + "\nContext passed to the `setup` method of `preboot` plugins." + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CorePreboot.analytics", + "type": "Object", + "tags": [], + "label": "analytics", + "description": [ + "{@link AnalyticsServicePreboot}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: (eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; registerEventType: (eventTypeOps: ", + "EventTypeOpts", + ") => void; registerShipper: (Shipper: ", + "ShipperClassConstructor", + ", shipperConfig: ShipperConfig, opts?: ", + "RegisterShipperOpts", + " | undefined) => void; registerContextProvider: (contextProviderOpts: ", + "ContextProviderOpts", + ") => void; removeContextProvider: (contextProviderName: string) => void; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CorePreboot.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [ + "{@link ElasticsearchServicePreboot}" + ], + "signature": [ + "ElasticsearchServicePreboot" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CorePreboot.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [ + "{@link HttpServicePreboot}" + ], + "signature": [ + "HttpServicePreboot", + "<", + "RequestHandlerContext", + ">" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CorePreboot.preboot", + "type": "Object", + "tags": [], + "label": "preboot", + "description": [ + "{@link PrebootServicePreboot}" + ], + "signature": [ + "PrebootServicePreboot" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup", + "type": "Interface", + "tags": [], + "label": "CoreSetup", + "description": [ + "\nContext passed to the `setup` method of `standard` plugins.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-server", + "scope": "server", + "docId": "kibKbnCoreLifecycleServerPluginApi", + "section": "def-server.CoreSetup", + "text": "CoreSetup" + }, + "" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.analytics", + "type": "Object", + "tags": [], + "label": "analytics", + "description": [ + "{@link AnalyticsServiceSetup}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: (eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; registerEventType: (eventTypeOps: ", + "EventTypeOpts", + ") => void; registerShipper: (Shipper: ", + "ShipperClassConstructor", + ", shipperConfig: ShipperConfig, opts?: ", + "RegisterShipperOpts", + " | undefined) => void; registerContextProvider: (contextProviderOpts: ", + "ContextProviderOpts", + ") => void; removeContextProvider: (contextProviderName: string) => void; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.capabilities", + "type": "Object", + "tags": [], + "label": "capabilities", + "description": [ + "{@link CapabilitiesSetup}" + ], + "signature": [ + "CapabilitiesSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.docLinks", + "type": "Object", + "tags": [], + "label": "docLinks", + "description": [ + "{@link DocLinksServiceSetup}" + ], + "signature": [ + "DocLinksServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [ + "{@link ElasticsearchServiceSetup}" + ], + "signature": [ + "ElasticsearchServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.executionContext", + "type": "Object", + "tags": [], + "label": "executionContext", + "description": [ + "{@link ExecutionContextSetup}" + ], + "signature": [ + "ExecutionContextSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.http", + "type": "CompoundType", + "tags": [], + "label": "http", + "description": [ + "{@link HttpServiceSetup}" + ], + "signature": [ + "HttpServiceSetup", + "<", + "RequestHandlerContext", + "> & { resources: ", + "HttpResources", + "; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.i18n", + "type": "Object", + "tags": [], + "label": "i18n", + "description": [ + "{@link I18nServiceSetup}" + ], + "signature": [ + "I18nServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.logging", + "type": "Object", + "tags": [], + "label": "logging", + "description": [ + "{@link LoggingServiceSetup}" + ], + "signature": [ + "LoggingServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.metrics", + "type": "Object", + "tags": [], + "label": "metrics", + "description": [ + "{@link MetricsServiceSetup}" + ], + "signature": [ + "MetricsServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.savedObjects", + "type": "Object", + "tags": [], + "label": "savedObjects", + "description": [ + "{@link SavedObjectsServiceSetup}" + ], + "signature": [ + "SavedObjectsServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.status", + "type": "Object", + "tags": [], + "label": "status", + "description": [ + "{@link StatusServiceSetup}" + ], + "signature": [ + "StatusServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [ + "{@link UiSettingsServiceSetup}" + ], + "signature": [ + "UiSettingsServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.deprecations", + "type": "Object", + "tags": [], + "label": "deprecations", + "description": [ + "{@link DeprecationsServiceSetup}" + ], + "signature": [ + "DeprecationsServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreSetup.getStartServices", + "type": "Function", + "tags": [], + "label": "getStartServices", + "description": [ + "{@link StartServicesAccessor}" + ], + "signature": [ + "() => Promise<[", + { + "pluginId": "@kbn/core-lifecycle-server", + "scope": "server", + "docId": "kibKbnCoreLifecycleServerPluginApi", + "section": "def-server.CoreStart", + "text": "CoreStart" + }, + ", TPluginsStart, TStart]>" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart", + "type": "Interface", + "tags": [], + "label": "CoreStart", + "description": [ + "\nContext passed to the plugins `start` method.\n" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.analytics", + "type": "Object", + "tags": [], + "label": "analytics", + "description": [ + "{@link AnalyticsServiceStart}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: (eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.capabilities", + "type": "Object", + "tags": [], + "label": "capabilities", + "description": [ + "{@link CapabilitiesStart}" + ], + "signature": [ + "CapabilitiesStart" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.docLinks", + "type": "Object", + "tags": [], + "label": "docLinks", + "description": [ + "{@link DocLinksServiceStart}" + ], + "signature": [ + "DocLinksServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [ + "{@link ElasticsearchServiceStart}" + ], + "signature": [ + "ElasticsearchServiceStart" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.executionContext", + "type": "Object", + "tags": [], + "label": "executionContext", + "description": [ + "{@link ExecutionContextStart}" + ], + "signature": [ + "ExecutionContextSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [ + "{@link HttpServiceStart}" + ], + "signature": [ + "HttpServiceStart" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.metrics", + "type": "Object", + "tags": [], + "label": "metrics", + "description": [ + "{@link MetricsServiceStart}" + ], + "signature": [ + "MetricsServiceSetup" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.savedObjects", + "type": "Object", + "tags": [], + "label": "savedObjects", + "description": [ + "{@link SavedObjectsServiceStart}" + ], + "signature": [ + "SavedObjectsServiceStart" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.CoreStart.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [ + "{@link UiSettingsServiceStart}" + ], + "signature": [ + "UiSettingsServiceStart" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_start.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-lifecycle-server", + "id": "def-server.StartServicesAccessor", + "type": "Type", + "tags": [], + "label": "StartServicesAccessor", + "description": [ + "\nAllows plugins to get access to APIs available in start inside async handlers.\nPromise will not resolve until Core and plugin dependencies have completed `start`.\nThis should only be used inside handlers registered during `setup` that will only be executed\nafter `start` lifecycle.\n" + ], + "signature": [ + "() => Promise<[", + { + "pluginId": "@kbn/core-lifecycle-server", + "scope": "server", + "docId": "kibKbnCoreLifecycleServerPluginApi", + "section": "def-server.CoreStart", + "text": "CoreStart" + }, + ", TPluginsStart, TStart]>" + ], + "path": "packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [], + "initialIsOpen": false + } + ], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx new file mode 100644 index 0000000000000..fd0edd1ec75b0 --- /dev/null +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCoreLifecycleServerPluginApi +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: 2022-10-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] +--- +import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 31 | 0 | 0 | 0 | + +## Server + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_lifecycle_server_mocks.devdocs.json b/api_docs/kbn_core_lifecycle_server_mocks.devdocs.json new file mode 100644 index 0000000000000..55aa54ec4fffa --- /dev/null +++ b/api_docs/kbn_core_lifecycle_server_mocks.devdocs.json @@ -0,0 +1,245 @@ +{ + "id": "@kbn/core-lifecycle-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreInternalLifecycleMock", + "type": "Object", + "tags": [], + "label": "coreInternalLifecycleMock", + "description": [], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreInternalLifecycleMock.createInternalPreboot", + "type": "Function", + "tags": [], + "label": "createInternalPreboot", + "description": [], + "signature": [ + "() => { analytics: jest.Mocked<", + "AnalyticsServicePreboot", + ">; context: jest.Mocked<", + "InternalContextSetup", + ">; elasticsearch: ", + "MockedElasticSearchServicePreboot", + "; http: ", + "InternalHttpServicePrebootMock", + "; httpResources: { createRegistrar: jest.Mock, []>; }; uiSettings: jest.Mocked<", + "InternalUiSettingsServicePreboot", + ">; logging: jest.Mocked<", + "InternalLoggingServicePreboot", + ">; preboot: ", + "InternalPrebootServicePrebootMock", + "; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreInternalLifecycleMock.createInternalSetup", + "type": "Function", + "tags": [], + "label": "createInternalSetup", + "description": [], + "signature": [ + "() => { analytics: jest.Mocked<", + "AnalyticsServiceSetup", + ">; capabilities: jest.Mocked<", + "CapabilitiesSetup", + ">; context: jest.Mocked<", + "InternalContextSetup", + ">; docLinks: ", + "DocLinksServiceSetup", + "; elasticsearch: ", + "MockedInternalElasticSearchServiceSetup", + "; http: ", + "InternalHttpServiceSetupMock", + "; savedObjects: jest.Mocked<", + "InternalSavedObjectsServiceSetup", + ">; status: jest.Mocked<", + "InternalStatusServiceSetup", + ">; environment: jest.Mocked<", + "InternalEnvironmentServicePreboot", + ">; i18n: jest.Mocked<", + "I18nServiceSetup", + ">; httpResources: { createRegistrar: jest.Mock, []>; }; rendering: jest.Mocked<", + "InternalRenderingServiceSetup", + ">; uiSettings: jest.Mocked<", + "UiSettingsServiceSetup", + ">; logging: jest.Mocked<", + "InternalLoggingServicePreboot", + ">; metrics: jest.Mocked<", + "MetricsServiceSetup", + ">; deprecations: jest.Mocked<", + "DeprecationRegistryProvider", + ">; executionContext: jest.Mocked<", + "IExecutionContext", + ">; coreUsageData: jest.Mocked<", + "InternalCoreUsageDataSetup", + ">; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreInternalLifecycleMock.createInternalStart", + "type": "Function", + "tags": [], + "label": "createInternalStart", + "description": [], + "signature": [ + "() => { analytics: jest.Mocked<", + "AnalyticsServiceStart", + ">; capabilities: jest.Mocked<", + "CapabilitiesStart", + ">; docLinks: ", + "DocLinksServiceSetup", + "; elasticsearch: ", + "MockedElasticSearchServiceStart", + "; http: ", + "InternalHttpServiceStartMock", + "; metrics: jest.Mocked<", + "MetricsServiceSetup", + ">; savedObjects: jest.Mocked<", + "SavedObjectsServiceStart", + ">; uiSettings: jest.Mocked<", + "UiSettingsServiceStart", + ">; coreUsageData: jest.Mocked<", + "CoreUsageDataStart", + ">; executionContext: jest.Mocked<", + "IExecutionContext", + ">; deprecations: jest.Mocked<", + "InternalDeprecationsServiceStart", + ">; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreLifecycleMock", + "type": "Object", + "tags": [], + "label": "coreLifecycleMock", + "description": [], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreLifecycleMock.createPreboot", + "type": "Function", + "tags": [], + "label": "createPreboot", + "description": [], + "signature": [ + "() => CorePrebootMockType" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreLifecycleMock.createCoreSetup", + "type": "Function", + "tags": [], + "label": "createCoreSetup", + "description": [], + "signature": [ + "({ pluginStartDeps, pluginStartContract, }?: { pluginStartDeps?: object | undefined; pluginStartContract?: any; }) => CoreSetupMockType" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreLifecycleMock.createCoreSetup.$1", + "type": "Object", + "tags": [], + "label": "__0", + "description": [], + "signature": [ + "{ pluginStartDeps?: object | undefined; pluginStartContract?: any; }" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/core-lifecycle-server-mocks", + "id": "def-server.coreLifecycleMock.createCoreStart", + "type": "Function", + "tags": [], + "label": "createCoreStart", + "description": [], + "signature": [ + "() => ", + "MockedKeys", + "<", + "CoreStart", + ">" + ], + "path": "packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx new file mode 100644 index 0000000000000..900c197c3ec01 --- /dev/null +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCoreLifecycleServerMocksPluginApi +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: 2022-10-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] +--- +import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 9 | 0 | 9 | 0 | + +## Server + +### Objects + + diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 0da05bb4264e5..6113701710e37 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2022-10-25 +date: 2022-10-27 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 676c5fd5dd38d..6a6184f69b789 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 6d66c79810f73..0ab41b0803443 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 9a3851599fef6..dc2b8a08bf6a9 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 0e3d2b3fca484..2d81f1ac5aeb2 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 1415b14a8cf92..75f7ec72d810e 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2022-10-25 +date: 2022-10-27 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 b63aec7277b8d..797638463f27b 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 f39dbb3bb78ad..5f4bd7ea60f1e 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 b2d6689f0e496..df099fdfa60b4 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 e828adcd26088..d898f6f36cb11 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2022-10-25 +date: 2022-10-27 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 8cef396b70f5a..6e2321a2ec310 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 e9a5a15b4a83e..6915d36b4b06b 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 0f5709318ce7f..fbc89615448c5 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 57b2aeba26822..0f47d81d3447a 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 bb99c045648cb..a138b9c01165a 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 d5f0fbadaca84..6607dfce71804 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 04c3b267d276b..db832acebacae 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 9d99952c7e017..13e244e8ce7ee 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 05dacbbef9b84..1cd413ad66299 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: 2022-10-25 +date: 2022-10-27 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 e6893cec31677..f26fced74942e 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: 2022-10-25 +date: 2022-10-27 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.devdocs.json b/api_docs/kbn_core_plugins_server.devdocs.json new file mode 100644 index 0000000000000..63fcf8fc2dbbc --- /dev/null +++ b/api_docs/kbn_core_plugins_server.devdocs.json @@ -0,0 +1,1097 @@ +{ + "id": "@kbn/core-plugins-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin", + "type": "Interface", + "tags": [ + "deprecated" + ], + "label": "AsyncPlugin", + "description": [ + "\nA plugin with asynchronous lifecycle methods.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.AsyncPlugin", + "text": "AsyncPlugin" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": true, + "removeBy": "8.8.0", + "trackAdoption": false, + "references": [], + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "(core: ", + "CoreSetup", + ", plugins: TPluginsSetup) => TSetup | Promise" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.setup.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreSetup", + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.setup.$2", + "type": "Uncategorized", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "TPluginsSetup" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.start", + "type": "Function", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "(core: ", + "CoreStart", + ", plugins: TPluginsStart) => TStart | Promise" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.start.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreStart" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.start.$2", + "type": "Uncategorized", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "TPluginsStart" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.AsyncPlugin.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "(() => void) | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin", + "type": "Interface", + "tags": [], + "label": "Plugin", + "description": [ + "\nThe interface that should be returned by a `PluginInitializer` for a `standard` plugin.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.Plugin", + "text": "Plugin" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "(core: ", + "CoreSetup", + ", plugins: TPluginsSetup) => TSetup" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.setup.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreSetup", + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.setup.$2", + "type": "Uncategorized", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "TPluginsSetup" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.start", + "type": "Function", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "(core: ", + "CoreStart", + ", plugins: TPluginsStart) => TStart" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.start.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreStart" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.start.$2", + "type": "Uncategorized", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "TPluginsStart" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.Plugin.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "(() => void) | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigDescriptor", + "type": "Interface", + "tags": [], + "label": "PluginConfigDescriptor", + "description": [ + "\nDescribes a plugin configuration properties.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PluginConfigDescriptor", + "text": "PluginConfigDescriptor" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigDescriptor.deprecations", + "type": "Function", + "tags": [], + "label": "deprecations", + "description": [ + "\nProvider for the {@link ConfigDeprecation} to apply to the plugin configuration." + ], + "signature": [ + "ConfigDeprecationProvider", + " | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigDescriptor.exposeToBrowser", + "type": "Object", + "tags": [], + "label": "exposeToBrowser", + "description": [ + "\nList of configuration properties that will be available on the client-side plugin." + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.ExposedToBrowserDescriptor", + "text": "ExposedToBrowserDescriptor" + }, + " | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigDescriptor.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema to use to validate the plugin configuration.\n\n{@link PluginConfigSchema}" + ], + "signature": [ + "Type", + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigDescriptor.exposeToUsage", + "type": "Object", + "tags": [], + "label": "exposeToUsage", + "description": [ + "\nExpose non-default configs to usage collection to be sent via telemetry.\nset a config to `true` to report the actual changed config value.\nset a config to `false` to report the changed config value as [redacted].\n\nAll changed configs except booleans and numbers will be reported\nas [redacted] unless otherwise specified.\n\n{@link MakeUsageFromSchema}" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.MakeUsageFromSchema", + "text": "MakeUsageFromSchema" + }, + " | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext", + "type": "Interface", + "tags": [], + "label": "PluginInitializerContext", + "description": [ + "\nContext that's available to plugins during initialization stage.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PluginInitializerContext", + "text": "PluginInitializerContext" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext.opaqueId", + "type": "Uncategorized", + "tags": [], + "label": "opaqueId", + "description": [], + "signature": [ + "symbol" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext.env", + "type": "Object", + "tags": [], + "label": "env", + "description": [], + "signature": [ + "{ mode: ", + "EnvironmentMode", + "; packageInfo: Readonly<", + "PackageInfo", + ">; instanceUuid: string; configs: readonly string[]; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext.node", + "type": "Object", + "tags": [], + "label": "node", + "description": [ + "\nAccess the configuration for this particular Kibana node.\nCan be used to determine which `roles` the current process was started with.\n" + ], + "signature": [ + "NodeInfo" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [ + "\n{@link LoggerFactory | logger factory} instance already bound to the plugin's logging context\n" + ], + "signature": [ + "LoggerFactory" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializerContext.config", + "type": "Object", + "tags": [], + "label": "config", + "description": [ + "\nAccessors for the plugin's configuration" + ], + "signature": [ + "{ legacy: { globalConfig$: ", + "Observable", + " moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly shardTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly pingTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; }>; path: Readonly<{ readonly data: string; }>; savedObjects: Readonly<{ readonly maxImportPayloadBytes: Readonly<{ isGreaterThan: (other: ", + "ByteSizeValue", + ") => boolean; isLessThan: (other: ", + "ByteSizeValue", + ") => boolean; isEqualTo: (other: ", + "ByteSizeValue", + ") => boolean; getValueInBytes: () => number; toString: (returnUnit?: ByteSizeValueUnit | undefined) => string; }>; }>; }>>; get: () => Readonly<{ elasticsearch: Readonly<{ readonly requestTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly shardTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly pingTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; }>; path: Readonly<{ readonly data: string; }>; savedObjects: Readonly<{ readonly maxImportPayloadBytes: Readonly<{ isGreaterThan: (other: ", + "ByteSizeValue", + ") => boolean; isLessThan: (other: ", + "ByteSizeValue", + ") => boolean; isEqualTo: (other: ", + "ByteSizeValue", + ") => boolean; getValueInBytes: () => number; toString: (returnUnit?: ByteSizeValueUnit | undefined) => string; }>; }>; }>; }; create: () => ", + "Observable", + "; get: () => T; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest", + "type": "Interface", + "tags": [], + "label": "PluginManifest", + "description": [ + "\nDescribes the set of required and optional properties plugin can define in its\nmandatory JSON manifest file.\n" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nIdentifier of the plugin. Must be a string in camelCase. Part of a plugin public contract.\nOther plugins leverage it to access plugin API, navigate to the plugin, etc." + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "\nVersion of the plugin." + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.kibanaVersion", + "type": "string", + "tags": [], + "label": "kibanaVersion", + "description": [ + "\nThe version of Kibana the plugin is compatible with, defaults to \"version\"." + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.type", + "type": "Enum", + "tags": [], + "label": "type", + "description": [ + "\nType of the plugin, defaults to `standard`." + ], + "signature": [ + "PluginType" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.configPath", + "type": "CompoundType", + "tags": [], + "label": "configPath", + "description": [ + "\nRoot {@link ConfigPath | configuration path} used by the plugin, defaults\nto \"id\" in snake_case format.\n" + ], + "signature": [ + "string | string[]" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.requiredPlugins", + "type": "Object", + "tags": [], + "label": "requiredPlugins", + "description": [ + "\nAn optional list of the other plugins that **must be** installed and enabled\nfor this plugin to function properly." + ], + "signature": [ + "readonly string[]" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.requiredBundles", + "type": "Object", + "tags": [], + "label": "requiredBundles", + "description": [ + "\nList of plugin ids that this plugin's UI code imports modules from that are\nnot in `requiredPlugins`.\n" + ], + "signature": [ + "readonly string[]" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.optionalPlugins", + "type": "Object", + "tags": [], + "label": "optionalPlugins", + "description": [ + "\nAn optional list of the other plugins that if installed and enabled **may be**\nleveraged by this plugin for some additional functionality but otherwise are\nnot required for this plugin to work properly." + ], + "signature": [ + "readonly string[]" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.ui", + "type": "boolean", + "tags": [], + "label": "ui", + "description": [ + "\nSpecifies whether plugin includes some client/browser specific functionality\nthat should be included into client bundle via `public/ui_plugin.js` file." + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.server", + "type": "boolean", + "tags": [], + "label": "server", + "description": [ + "\nSpecifies whether plugin includes some server-side specific functionality." + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.extraPublicDirs", + "type": "Array", + "tags": [ + "deprecated" + ], + "label": "extraPublicDirs", + "description": [ + "\nSpecifies directory names that can be imported by other ui-plugins built\nusing the same instance of the @kbn/optimizer. A temporary measure we plan\nto replace with better mechanisms for sharing static code between plugins" + ], + "signature": [ + "string[] | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": true, + "trackAdoption": false, + "references": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.serviceFolders", + "type": "Object", + "tags": [], + "label": "serviceFolders", + "description": [ + "\nOnly used for the automatically generated API documentation. Specifying service\nfolders will cause your plugin API reference to be broken up into sub sections." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.owner", + "type": "Object", + "tags": [], + "label": "owner", + "description": [], + "signature": [ + "{ readonly name: string; readonly githubTeam?: string | undefined; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.description", + "type": "string", + "tags": [], + "label": "description", + "description": [ + "\nTODO: make required once all plugins specify this.\nA brief description of what this plugin does and any capabilities it provides." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginManifest.enabledOnAnonymousPages", + "type": "CompoundType", + "tags": [], + "label": "enabledOnAnonymousPages", + "description": [ + "\nSpecifies whether this plugin - and its required dependencies - will be enabled for anonymous pages (login page, status page when\nconfigured, etc.) Default is false." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PrebootPlugin", + "type": "Interface", + "tags": [], + "label": "PrebootPlugin", + "description": [ + "\nThe interface that should be returned by a `PluginInitializer` for a `preboot` plugin.\n" + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PrebootPlugin", + "text": "PrebootPlugin" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PrebootPlugin.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "(core: ", + "CorePreboot", + ", plugins: TPluginsSetup) => TSetup" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PrebootPlugin.setup.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CorePreboot" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PrebootPlugin.setup.$2", + "type": "Uncategorized", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "TPluginsSetup" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PrebootPlugin.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "(() => void) | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.ExposedToBrowserDescriptor", + "type": "Type", + "tags": [], + "label": "ExposedToBrowserDescriptor", + "description": [ + "\nType defining the list of configuration properties that will be exposed on the client-side\nObject properties can either be fully exposed\n" + ], + "signature": [ + "{ [Key in keyof T]?: (T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.ExposedToBrowserDescriptor", + "text": "ExposedToBrowserDescriptor" + }, + " : boolean) | undefined; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.MakeUsageFromSchema", + "type": "Type", + "tags": [], + "label": "MakeUsageFromSchema", + "description": [ + "\nList of configuration values that will be exposed to usage collection.\nIf parent node or actual config path is set to `true` then the actual value\nof these configs will be reoprted.\nIf parent node or actual config path is set to `false` then the config\nwill be reported as [redacted].\n" + ], + "signature": [ + "{ [Key in keyof T]?: (T[Key] extends Maybe ? false : T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.MakeUsageFromSchema", + "text": "MakeUsageFromSchema" + }, + " : boolean) | undefined; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginConfigSchema", + "type": "Type", + "tags": [], + "label": "PluginConfigSchema", + "description": [ + "\nDedicated type for plugin configuration schema.\n" + ], + "signature": [ + "Type", + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializer", + "type": "Type", + "tags": [], + "label": "PluginInitializer", + "description": [ + "\nThe `plugin` export at the root of a plugin's `server` directory should conform\nto this interface.\n" + ], + "signature": [ + "(core: ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PluginInitializerContext", + "text": "PluginInitializerContext" + }, + ") => ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.Plugin", + "text": "Plugin" + }, + " | ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PrebootPlugin", + "text": "PrebootPlugin" + }, + " | ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.AsyncPlugin", + "text": "AsyncPlugin" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.PluginInitializer.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "server", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-server.PluginInitializerContext", + "text": "PluginInitializerContext" + }, + "" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.SharedGlobalConfig", + "type": "Type", + "tags": [], + "label": "SharedGlobalConfig", + "description": [], + "signature": [ + "{ readonly elasticsearch: Readonly<{ readonly requestTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly shardTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; readonly pingTimeout: Readonly<{ clone: () => moment.Duration; humanize: { (argWithSuffix?: boolean | undefined, argThresholds?: moment.argThresholdOpts | undefined): string; (argThresholds?: moment.argThresholdOpts | undefined): string; }; abs: () => moment.Duration; as: (units: moment.unitOfTime.Base) => number; get: (units: moment.unitOfTime.Base) => number; milliseconds: () => number; asMilliseconds: () => number; seconds: () => number; asSeconds: () => number; minutes: () => number; asMinutes: () => number; hours: () => number; asHours: () => number; days: () => number; asDays: () => number; weeks: () => number; asWeeks: () => number; months: () => number; asMonths: () => number; years: () => number; asYears: () => number; add: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; subtract: (inp?: moment.DurationInputArg1, unit?: moment.unitOfTime.DurationConstructor | undefined) => moment.Duration; locale: { (): string; (locale: moment.LocaleSpecifier): moment.Duration; }; localeData: () => moment.Locale; toISOString: () => string; toJSON: () => string; isValid: () => boolean; lang: { (locale: moment.LocaleSpecifier): moment.Moment; (): moment.Locale; }; toIsoString: () => string; }>; }>; readonly path: Readonly<{ readonly data: string; }>; readonly savedObjects: Readonly<{ readonly maxImportPayloadBytes: Readonly<{ isGreaterThan: (other: ", + "ByteSizeValue", + ") => boolean; isLessThan: (other: ", + "ByteSizeValue", + ") => boolean; isEqualTo: (other: ", + "ByteSizeValue", + ") => boolean; getValueInBytes: () => number; toString: (returnUnit?: ByteSizeValueUnit | undefined) => string; }>; }>; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.SharedGlobalConfigKeys", + "type": "Object", + "tags": [], + "label": "SharedGlobalConfigKeys", + "description": [], + "path": "packages/core/plugins/core-plugins-server/src/shared_global_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.SharedGlobalConfigKeys.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [ + "// We can add more if really needed" + ], + "signature": [ + "readonly [\"shardTimeout\", \"requestTimeout\", \"pingTimeout\"]" + ], + "path": "packages/core/plugins/core-plugins-server/src/shared_global_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.SharedGlobalConfigKeys.path", + "type": "Object", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "readonly [\"data\"]" + ], + "path": "packages/core/plugins/core-plugins-server/src/shared_global_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-server.SharedGlobalConfigKeys.savedObjects", + "type": "Object", + "tags": [], + "label": "savedObjects", + "description": [], + "signature": [ + "readonly [\"maxImportPayloadBytes\"]" + ], + "path": "packages/core/plugins/core-plugins-server/src/shared_global_config.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx new file mode 100644 index 0000000000000..51f576d18fed4 --- /dev/null +++ b/api_docs/kbn_core_plugins_server.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCorePluginsServerPluginApi +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: 2022-10-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] +--- +import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 58 | 0 | 26 | 0 | + +## Server + +### Objects + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_plugins_server_mocks.devdocs.json b/api_docs/kbn_core_plugins_server_mocks.devdocs.json new file mode 100644 index 0000000000000..e7e11c0504caa --- /dev/null +++ b/api_docs/kbn_core_plugins_server_mocks.devdocs.json @@ -0,0 +1,107 @@ +{ + "id": "@kbn/core-plugins-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-plugins-server-mocks", + "id": "def-server.pluginServiceMock", + "type": "Object", + "tags": [], + "label": "pluginServiceMock", + "description": [], + "path": "packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-plugins-server-mocks", + "id": "def-server.pluginServiceMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => PluginsServiceMock" + ], + "path": "packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server-mocks", + "id": "def-server.pluginServiceMock.createSetupContract", + "type": "Function", + "tags": [], + "label": "createSetupContract", + "description": [], + "signature": [ + "() => ", + "PluginsServiceSetup" + ], + "path": "packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server-mocks", + "id": "def-server.pluginServiceMock.createStartContract", + "type": "Function", + "tags": [], + "label": "createStartContract", + "description": [], + "signature": [ + "() => { contracts: Map; }" + ], + "path": "packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-plugins-server-mocks", + "id": "def-server.pluginServiceMock.createUiPlugins", + "type": "Function", + "tags": [], + "label": "createUiPlugins", + "description": [], + "signature": [ + "() => { browserConfigs: Map; internal: Map; public: Map; }" + ], + "path": "packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx new file mode 100644 index 0000000000000..84795962d95f4 --- /dev/null +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCorePluginsServerMocksPluginApi +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: 2022-10-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] +--- +import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 5 | 0 | 5 | 0 | + +## Server + +### Objects + + diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index aa6f7b411df15..7e2bd637ba5e6 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2022-10-25 +date: 2022-10-27 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 6bd0c8018cf40..c13943e7cb4cc 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 8e928b38d3ca8..c1f2d33838f78 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: 2022-10-25 +date: 2022-10-27 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 5785f1a688416..fc3536fa21756 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: 2022-10-25 +date: 2022-10-27 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 6aecd30d2f93d..287636e6d041d 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: 2022-10-25 +date: 2022-10-27 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_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index bc8b99be1a1ab..07b29d82a08a4 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 aef4200a17976..c63b6735bb2a6 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2022-10-25 +date: 2022-10-27 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_internal.mdx b/api_docs/kbn_core_saved_objects_api_server_internal.mdx index 4cb67c84a5a56..2dfc962709cb2 100644 --- a/api_docs/kbn_core_saved_objects_api_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-internal title: "@kbn/core-saved-objects-api-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-internal plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-internal'] --- import kbnCoreSavedObjectsApiServerInternalObj from './kbn_core_saved_objects_api_server_internal.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 56921271693fe..9653115a36709 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: 2022-10-25 +date: 2022-10-27 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 ab1e5ed664f76..fc1451a1120dd 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: 2022-10-25 +date: 2022-10-27 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 8fe7f7121f77a..5c5c24028aa56 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: 2022-10-25 +date: 2022-10-27 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 8438fa6c4e1be..0097116279d5b 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 9a720870eb797..45dd67d7de0fe 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 e801344422ab7..66e2a3498e5b5 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 d0e947abfc063..28123d66e72b6 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2022-10-25 +date: 2022-10-27 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 88bbe5fdb850d..4f264eb6ba3dd 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: 2022-10-25 +date: 2022-10-27 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 b9f8481677baa..35c85a196bda5 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: 2022-10-25 +date: 2022-10-27 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 1d7afa9cb74d4..e9054f5ddac0d 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: 2022-10-25 +date: 2022-10-27 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 a1c9666518adb..ae39f9274383d 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: 2022-10-25 +date: 2022-10-27 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 dfd50e0069d8a..ccbd986403a12 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2022-10-25 +date: 2022-10-27 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 22a7b1895b3fd..839a20bb8de36 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: 2022-10-25 +date: 2022-10-27 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 51425bcc150ff..6f5d06ad2b941 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: 2022-10-25 +date: 2022-10-27 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 7938ab6338fc3..bd4852894104d 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: 2022-10-25 +date: 2022-10-27 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 9fea7d66efb4e..946aa201abb92 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: 2022-10-25 +date: 2022-10-27 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 1ba438eba1288..4871aa5dbf836 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: 2022-10-25 +date: 2022-10-27 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 f8d74d837a1e6..65c4b49cc470f 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: 2022-10-25 +date: 2022-10-27 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 f0d7760a84ea2..836cfcbf72d4e 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: 2022-10-25 +date: 2022-10-27 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 8ff12b4bf4031..bc3a711c881b2 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: 2022-10-25 +date: 2022-10-27 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 5308f2fcbfbef..4c82257440566 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2022-10-25 +date: 2022-10-27 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 356a6fbe78bb5..d2b9679b27485 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2022-10-25 +date: 2022-10-27 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_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 10a811b69d2a9..ea7fcee358535 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: 2022-10-25 +date: 2022-10-27 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 fbe12213a11fa..33f8554abc430 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: 2022-10-25 +date: 2022-10-27 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 b7752345297c4..7d06a917fea76 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 6bce0e96a9d97..c06f92445d910 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 f0fbac738ed99..6915b72b847f0 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 8aae5f3a219dc..428f0ff8cba7b 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2022-10-25 +date: 2022-10-27 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 ee733af4f8c2b..b2e3b263a1e12 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2022-10-25 +date: 2022-10-27 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 86e45bb6eda70..24937e248cf85 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 d20a360cf655d..d021de220cde3 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2022-10-25 +date: 2022-10-27 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 222ba821dce2f..255a43d04b5f7 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: 2022-10-25 +date: 2022-10-27 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 2b0de5459cc6f..d8d991b65676f 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: 2022-10-25 +date: 2022-10-27 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 50600bcf64e04..d5d48e7fab1f6 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: 2022-10-25 +date: 2022-10-27 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 6f2009e53efd2..f4cd19d007398 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: 2022-10-25 +date: 2022-10-27 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 030bd72752622..0c8f8a0669504 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: 2022-10-25 +date: 2022-10-27 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 7bfb3657f332f..28ff986dadff2 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: 2022-10-25 +date: 2022-10-27 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_crypto.mdx b/api_docs/kbn_crypto.mdx index 70733fc6323c7..7ab25ffd5d55b 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2022-10-25 +date: 2022-10-27 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 2265f542a2a21..547cb2dd95c51 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index ec8346d8c9cac..978e44f341937 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2022-10-25 +date: 2022-10-27 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 ffd87d191394f..1d66e07c0d9ad 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2022-10-25 +date: 2022-10-27 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 92fdd8cfdb11f..e21e1f9121950 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2022-10-25 +date: 2022-10-27 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 db8024bc9d65b..4d0e6133ab751 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2022-10-25 +date: 2022-10-27 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 797835d7989c0..83a050a930540 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index a12b3ae2f8792..59846f75e673f 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -160,7 +160,7 @@ "label": "apm", "description": [], "signature": [ - "{ readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; readonly overview: string; readonly tailSamplingPolicies: string; readonly elasticAgent: string; }" + "{ readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; readonly overview: string; readonly tailSamplingPolicies: string; readonly elasticAgent: string; readonly storageExplorer: string; readonly spanCompression: string; readonly transactionSampling: string; readonly indexLifecycleManagement: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 7ffc904db03f2..dc4559557ade6 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2022-10-25 +date: 2022-10-27 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 f939d98888dae..347e99141ab8c 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index ba5965a75fcc0..1b7516969bda4 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index ce09dbcd5efc1..0ac44d607848e 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2022-10-25 +date: 2022-10-27 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 e0b0502022dd5..61123022d414b 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2022-10-25 +date: 2022-10-27 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 2525f0d411df4..c107cd654437a 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2022-10-25 +date: 2022-10-27 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 881d5c5e06cd2..a542cc1e36085 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: 2022-10-25 +date: 2022-10-27 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 e4e4b3092a0d7..ee8d5c6b0659b 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 8d27a38047739..40fbf2a84b17a 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2022-10-25 +date: 2022-10-27 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 5305014c72b76..6895e16b968d7 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2022-10-25 +date: 2022-10-27 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 3890e5602da1a..9978753506a21 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: 2022-10-25 +date: 2022-10-27 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 e369d2555111e..17c948b9c7077 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index ecb9a6679ca54..bb6c09725c4cf 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index da17ae4a2498a..7f7fa468a89d6 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: 2022-10-25 +date: 2022-10-27 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 d58614328550e..15f2ee2eb0fdd 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2022-10-25 +date: 2022-10-27 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 1040ec7db227b..d8baa5c80d644 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 2d31773beaaa0..0a336e791151b 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2022-10-25 +date: 2022-10-27 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 3239fffc035bf..75a09df57f806 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2022-10-25 +date: 2022-10-27 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 957110288ffe5..d04acc3a80f60 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 0380a399cd775..3e5055b1d0ca3 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 2406a0e382f6e..1b5413a3cf985 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2022-10-25 +date: 2022-10-27 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 5f170cdd04715..fe0c11bb61a79 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 fde2dcb60dc53..74d33a8eeedad 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2022-10-25 +date: 2022-10-27 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 85587805fc4d0..f638de14134ee 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 77fcb7c94195c..e697201146686 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2022-10-25 +date: 2022-10-27 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 c037eb35a57a6..73e95c810101a 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: 2022-10-25 +date: 2022-10-27 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 a8e7e11cba0ac..e2000be3c7763 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2022-10-25 +date: 2022-10-27 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 50e5a40635291..09c885353218c 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 35e73b03dd323..b0bbe3723f285 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2022-10-25 +date: 2022-10-27 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 e84c326379ae0..383e914616ccc 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.devdocs.json b/api_docs/kbn_ml_agg_utils.devdocs.json index 6c021a7a5bc78..efb59fbc5c166 100644 --- a/api_docs/kbn_ml_agg_utils.devdocs.json +++ b/api_docs/kbn_ml_agg_utils.devdocs.json @@ -87,7 +87,7 @@ }, "[], samplerShardSize: number, runtimeMappings?: ", "MappingRuntimeFields", - " | undefined) => Promise<", + " | undefined, abortSignal?: AbortSignal | undefined) => Promise<", { "pluginId": "@kbn/ml-agg-utils", "scope": "server", @@ -198,6 +198,21 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/ml-agg-utils", + "id": "def-server.fetchAggIntervals.$7", + "type": "Object", + "tags": [], + "label": "abortSignal", + "description": [], + "signature": [ + "AbortSignal | undefined" + ], + "path": "x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -225,7 +240,7 @@ }, ", samplerShardSize: number, runtimeMappings?: ", "MappingRuntimeFields", - " | undefined) => Promise<(", + " | undefined, abortSignal?: AbortSignal | undefined) => Promise<(", "NumericChartData", " | OrdinalChartData | UnsupportedChartData)[]>" ], @@ -341,6 +356,21 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/ml-agg-utils", + "id": "def-server.fetchHistogramsForFields.$7", + "type": "Object", + "tags": [], + "label": "abortSignal", + "description": [], + "signature": [ + "AbortSignal | undefined" + ], + "path": "x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [ diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 514f5d0224235..f975e0adcf2dd 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact Machine Learning UI for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 64 | 2 | 44 | 3 | +| 66 | 2 | 46 | 3 | ## Server diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 0e13cded4d10e..961a4452bb2eb 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 447c4fe55fa29..0c344b5cfa6da 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 747b0372a7b9d..a73369d84cdc5 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 35f8a0d7bd223..9af26a966a2bf 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2022-10-25 +date: 2022-10-27 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 1f5f3347cf82b..3739d7fef07d1 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2022-10-25 +date: 2022-10-27 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 ec4bcda7cb2e3..3a551f5fe0893 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: 2022-10-25 +date: 2022-10-27 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 cc8cd64c1cb68..39fe312208428 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2022-10-25 +date: 2022-10-27 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 403160feced5b..dab05c3a8542e 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2022-10-25 +date: 2022-10-27 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 9a0282723d003..a4273b7613503 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index e1565bda96154..7a373678f9a02 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index fb0fd0854d7c9..0ebac27d67bfb 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 60b276fad7485..91e1cf13a225b 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index cc317aa7c6177..8700c9e8a4c5e 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 0a12259158109..1421325227eca 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 3965f87b59964..38fd6d15bb426 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: 2022-10-25 +date: 2022-10-27 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_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index c5559011b9b1e..1e36f71d583e6 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 6395418ad396f..59b33d3511299 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2022-10-25 +date: 2022-10-27 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 e4a1cf4434d20..ec17673720285 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2022-10-25 +date: 2022-10-27 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 c4161d87e1b2b..1a7c9d4e3e3ec 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2022-10-25 +date: 2022-10-27 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 b64737ba39937..9bdd8bf2fdfcf 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 37e83e636efbf..aa11e861c185c 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2022-10-25 +date: 2022-10-27 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 1733463d4a55a..89d2a42208cb6 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2022-10-25 +date: 2022-10-27 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 74300dfa8df69..df230d069323e 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2022-10-25 +date: 2022-10-27 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 3ec6c5a5530b6..51d7dcb313441 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 59882a0487cee..9f217f89910a5 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2022-10-25 +date: 2022-10-27 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 e1dbd2cdcfa4c..9d4c93b381232 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2022-10-25 +date: 2022-10-27 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 6ddf58d969696..0eae5ed3cc6bd 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2022-10-25 +date: 2022-10-27 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 9f5809200ac42..a0c2843feb485 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2022-10-25 +date: 2022-10-27 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 742cc439e05f2..540d0b120c7c4 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 3f34410c6560e..e3ef1838c580a 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2022-10-25 +date: 2022-10-27 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_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index b0b96a695dc07..473457102bbe2 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: 2022-10-25 +date: 2022-10-27 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_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index d1fae19cb6fe8..772c22bf6f3dc 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 e0abd3d4fac70..c242fbbdf3e23 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2022-10-25 +date: 2022-10-27 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 830a6eb0ade89..2b4cb3c1300e1 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2022-10-25 +date: 2022-10-27 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 248d2004953e9..ed538f0f19bef 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 3c55946545e62..e9f801ccfd8a1 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 8dcfea6717864..2bbbd1a44b820 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: 2022-10-25 +date: 2022-10-27 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 e84ba879c741e..87a7a99ebb6a7 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: 2022-10-25 +date: 2022-10-27 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 a650a7ca792c1..625678a76d86f 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2022-10-25 +date: 2022-10-27 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 6c37828d4cc2e..1eaac38267408 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 660e4aa491a81..b747c92281a13 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2022-10-25 +date: 2022-10-27 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 b2591c5fa6518..8c717b1f396d4 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 9485665753b8f..d33db8b876a70 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2022-10-25 +date: 2022-10-27 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 bb567608bcb83..23a5a4745149c 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 12d47a7c0e8bc..c67224718bed8 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2022-10-25 +date: 2022-10-27 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 57d27b4c6fc34..1089b4de5732d 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2022-10-25 +date: 2022-10-27 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 f68c69ac5b8d9..d223d911d4d3c 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 d84975cfabd6c..f66c631487e94 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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 c4f9865bdcf6c..443e347881498 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2022-10-25 +date: 2022-10-27 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 de091d050d0b1..06b521722dd1b 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2022-10-25 +date: 2022-10-27 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 9c5fd565d1934..38ebbe56715cb 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2022-10-25 +date: 2022-10-27 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_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 29bbc868d7108..ff77a93f41a32 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: 2022-10-25 +date: 2022-10-27 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 e6e11c1428f15..ae8dd4550531c 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: 2022-10-25 +date: 2022-10-27 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 f6bc6a8760f65..a2cffb01929a1 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: 2022-10-25 +date: 2022-10-27 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 79a277f3c4d5f..e168d27763943 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2022-10-25 +date: 2022-10-27 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 e9dd81e1b999c..73b58d0e58431 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 30b1af925cb49..2027933ae6b53 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index 552050e6a93bd..8c09347bc9c3c 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 47285c7067612..297e65d5d104a 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2022-10-25 +date: 2022-10-27 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 899aa1a5665ff..d7d05aaa61e4a 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2022-10-25 +date: 2022-10-27 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 a9c17de3616f3..92c7f062e2568 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2022-10-25 +date: 2022-10-27 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 29483e055b9dd..826b8156b68ed 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2022-10-25 +date: 2022-10-27 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 7ce67ac6c1d48..790282f8889ff 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2022-10-25 +date: 2022-10-27 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 1c18f3ac574de..739935fa250a4 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2022-10-25 +date: 2022-10-27 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 7e6bd9b5a1e48..c9d6e62f0564e 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 0edc5d92f4e59..ca984b5dd648e 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index 764a969b54594..f42dc731221e1 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index 6964f368a1461..9027787fe4002 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index b3017501cd787..54c42b5300b3d 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 9be8498892de8..4d7924bca7ef1 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index a78215759deb6..b23721515b9b9 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2022-10-25 +date: 2022-10-27 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 8569c6d217fd0..adafffa3d6001 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2022-10-25 +date: 2022-10-27 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 0979bb2faf3d4..9c8079bbe74c6 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2022-10-25 +date: 2022-10-27 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 631388b71d539..2a7427c92aaf0 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2022-10-25 +date: 2022-10-27 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 8e776d28e3254..68c90b1f162c2 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2022-10-25 +date: 2022-10-27 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 d6861ce5e4b2c..d5b57a7c2821f 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2022-10-25 +date: 2022-10-27 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 9cd7b80a16842..4b693f7a2a4cc 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2022-10-25 +date: 2022-10-27 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 018bd49236a69..cd85dbae95427 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2022-10-25 +date: 2022-10-27 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 f829fc640cc84..4cbb2c132a1e2 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 6269a6ceded42..fb2f5a68611e2 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -9464,13 +9464,7 @@ "text": "LensServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "lens", @@ -9510,13 +9504,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", { "pluginId": "lens", @@ -9571,13 +9559,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", { "pluginId": "lens", @@ -9626,13 +9608,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", plugins: ", { "pluginId": "lens", @@ -9655,13 +9631,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "x-pack/plugins/lens/server/plugin.tsx", "deprecated": false, diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index c7cdf0864febb..69861c54024cc 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2022-10-25 +date: 2022-10-27 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 4bbf39933b472..d7dbd837b77c5 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2022-10-25 +date: 2022-10-27 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 b31f55700f7be..2dd396e494dbd 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2022-10-25 +date: 2022-10-27 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 ef8104ccbd7f9..b674e1d2d3cfe 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2022-10-25 +date: 2022-10-27 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 32695ef58dabc..b5287376c9796 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2022-10-25 +date: 2022-10-27 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 12f1093d614da..aba0560e1bf7c 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2022-10-25 +date: 2022-10-27 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 7593f6f13b58e..d91fe6db2ce47 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.devdocs.json b/api_docs/maps_ems.devdocs.json index ef117f9582be4..3479c443f5f13 100644 --- a/api_docs/maps_ems.devdocs.json +++ b/api_docs/maps_ems.devdocs.json @@ -433,13 +433,7 @@ "text": "MapsEmsPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "mapsEms", @@ -462,13 +456,7 @@ "label": "_initializerContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "; }>; includeElasticMapsService: boolean; emsUrl: string; emsFileApiUrl: string; emsTileApiUrl: string; emsLandingPageUrl: string; emsFontLibraryUrl: string; emsTileLayerId: Readonly<{} & { dark: string; bright: string; desaturated: string; }>; }>>" ], "path": "src/plugins/maps_ems/server/index.ts", @@ -497,13 +485,7 @@ "label": "initializerContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "; }>; includeElasticMapsService: boolean; emsUrl: string; emsFileApiUrl: string; emsTileApiUrl: string; emsLandingPageUrl: string; emsFontLibraryUrl: string; emsTileLayerId: Readonly<{} & { dark: string; bright: string; desaturated: string; }>; }>>" ], "path": "src/plugins/maps_ems/server/index.ts", @@ -523,13 +505,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", plugins: MapsEmsSetupServerDependencies) => { config: Readonly<{} & { tilemap: Readonly<{ url?: string | undefined; } & { options: Readonly<{ default?: boolean | undefined; tileSize?: number | undefined; subdomains?: string[] | undefined; errorTileUrl?: string | undefined; tms?: boolean | undefined; reuseTiles?: boolean | undefined; bounds?: number[] | undefined; } & { attribution: string; minZoom: number; maxZoom: number; }>; }>; includeElasticMapsService: boolean; emsUrl: string; emsFileApiUrl: string; emsTileApiUrl: string; emsLandingPageUrl: string; emsFontLibraryUrl: string; emsTileLayerId: Readonly<{} & { dark: string; bright: string; desaturated: string; }>; }>; createEMSSettings: () => ", { "pluginId": "mapsEms", @@ -552,13 +528,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], "path": "src/plugins/maps_ems/server/index.ts", diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index ac31ad27cec25..fb61737234619 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2022-10-25 +date: 2022-10-27 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 a50776d2a8229..4676f44f78871 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2022-10-25 +date: 2022-10-27 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 cf12fa46ed6b4..9fe0edd8ff4dc 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2022-10-25 +date: 2022-10-27 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 e3aa933417662..71a7f13031ad8 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2022-10-25 +date: 2022-10-27 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 9ee59b29bb14e..829c455f7c3ae 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2022-10-25 +date: 2022-10-27 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 21d8ec2530ee4..82bf25ca27072 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 17f675ec05965..c9d8b2c0def40 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -7550,21 +7550,9 @@ "description": [], "signature": [ "{ start: () => Promise<", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ">; setup: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "; }" ], "path": "x-pack/plugins/observability/server/routes/types.ts", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index a711fde1e932e..f7521758efba9 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 806bbf96dc01f..bd8a1d7090a48 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2022-10-25 +date: 2022-10-27 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 3668c19af7342..b33b622ccd952 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,23 +15,23 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 497 | 412 | 38 | +| 503 | 416 | 38 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 32671 | 179 | 21959 | 1033 | +| 32804 | 179 | 21997 | 1039 | ## Plugin Directory | Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| -| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 214 | 0 | 209 | 23 | +| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 225 | 0 | 220 | 24 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 1 | 32 | 2 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 9 | 0 | 0 | 2 | -| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 382 | 0 | 373 | 24 | -| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 38 | 0 | 38 | 53 | +| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 382 | 0 | 373 | 26 | +| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 38 | 0 | 38 | 56 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 81 | 1 | 72 | 2 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | @@ -45,8 +45,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | cloudLinks | [Kibana Core](https://github.com/orgs/elastic/teams/@kibana-core) | Adds the links to the Elastic Cloud console | 0 | 0 | 0 | 0 | | | [Cloud Security Posture](https://github.com/orgs/elastic/teams/cloud-posture-security) | The cloud security posture plugin | 18 | 0 | 2 | 3 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 13 | 0 | 13 | 1 | -| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 229 | 0 | 220 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2697 | 0 | 23 | 0 | +| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 233 | 0 | 224 | 7 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2700 | 0 | 0 | 0 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 107 | 0 | 88 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 121 | 0 | 114 | 3 | @@ -81,10 +81,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 7 | 0 | 7 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 159 | 0 | 149 | 9 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds expression runtime to Kibana | 2191 | 17 | 1734 | 5 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 222 | 0 | 95 | 2 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 227 | 0 | 96 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 288 | 5 | 249 | 3 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 62 | 0 | 62 | 2 | -| | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/team:AppServicesUx) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 272 | 0 | 18 | 2 | +| | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/team:AppServicesUx) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 271 | 0 | 18 | 2 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 996 | 3 | 893 | 17 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | @@ -180,7 +180,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the vislib visualizations. These are the classical area/line/bar, pie, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 26 | 0 | 25 | 1 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 53 | 0 | 50 | 5 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 759 | 12 | 729 | 18 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 760 | 12 | 730 | 18 | | watcher | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | ## Package Directory @@ -233,7 +233,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 5 | 0 | 0 | 0 | | | Kibana Core | - | 16 | 0 | 7 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | -| | Kibana Core | - | 114 | 0 | 41 | 0 | +| | Kibana Core | - | 119 | 0 | 43 | 0 | | | Kibana Core | - | 3 | 0 | 3 | 0 | | | Kibana Core | - | 4 | 0 | 4 | 0 | | | Kibana Core | - | 9 | 0 | 3 | 0 | @@ -288,6 +288,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 4 | 0 | 4 | 0 | | | Kibana Core | - | 28 | 0 | 0 | 0 | | | Kibana Core | - | 5 | 0 | 5 | 0 | +| | Kibana Core | - | 31 | 0 | 0 | 0 | +| | Kibana Core | - | 9 | 0 | 9 | 0 | | | Kibana Core | - | 56 | 0 | 30 | 0 | | | Kibana Core | - | 9 | 0 | 5 | 1 | | | Kibana Core | - | 13 | 0 | 12 | 0 | @@ -308,6 +310,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 3 | 0 | 3 | 0 | | | Kibana Core | - | 14 | 0 | 10 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | +| | Kibana Core | - | 58 | 0 | 26 | 0 | +| | Kibana Core | - | 5 | 0 | 5 | 0 | | | Kibana Core | - | 5 | 0 | 0 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 2 | 0 | 2 | 0 | @@ -390,7 +394,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 8 | 0 | 8 | 0 | | | [Owner missing] | - | 6 | 0 | 1 | 1 | | | [Owner missing] | - | 534 | 1 | 1 | 0 | -| | Machine Learning UI | This package includes utility functions related to creating elasticsearch aggregation queries, data manipulation and verification. | 64 | 2 | 44 | 3 | +| | Machine Learning UI | This package includes utility functions related to creating elasticsearch aggregation queries, data manipulation and verification. | 66 | 2 | 46 | 3 | | | Machine Learning UI | A type guard to check record like object structures. | 3 | 0 | 2 | 0 | | | Machine Learning UI | Creates a deterministic number based hash out of a string. | 2 | 0 | 1 | 0 | | | [Owner missing] | - | 55 | 0 | 55 | 2 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index ca086cdb2e5d5..ce40f6a9731df 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2022-10-25 +date: 2022-10-27 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 71a0d463ce06c..ffae14439f459 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: 2022-10-25 +date: 2022-10-27 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 cce9bd68dd9bb..950847ee149ca 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2022-10-25 +date: 2022-10-27 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 1601ba2ad849a..7c070d808186d 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2022-10-25 +date: 2022-10-27 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 88e87b7bdd146..7bb6fb89cc4ca 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2022-10-25 +date: 2022-10-27 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 1ba9e57626212..1b69ab9be749a 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2022-10-25 +date: 2022-10-27 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 cba8d6a5fe6fc..743a82e9a2dd2 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2022-10-25 +date: 2022-10-27 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 4aab589645a9c..d6b1dd0234466 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2022-10-25 +date: 2022-10-27 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 aec499b35e4cb..cff827c69b9ef 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: 2022-10-25 +date: 2022-10-27 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 f5b9728277aee..e131778d3904f 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2022-10-25 +date: 2022-10-27 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 3a10b3cf465bc..483b4fcb62e4a 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2022-10-25 +date: 2022-10-27 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 3a57068b40de1..cc14564308e63 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2022-10-25 +date: 2022-10-27 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 d6d5f61f71f05..77970589d361d 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2022-10-25 +date: 2022-10-27 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 84708e421c3d8..06815f8335cb4 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2022-10-25 +date: 2022-10-27 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 20c41d9d0ead0..85dc9d9046c38 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2022-10-25 +date: 2022-10-27 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 592b19eaa34a6..0cff94e1dc566 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2022-10-25 +date: 2022-10-27 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 db510724f2984..b2794eb58fe05 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -1390,13 +1390,7 @@ "text": "Plugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "securitySolution", @@ -1445,13 +1439,7 @@ "label": "context", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], "path": "x-pack/plugins/security_solution/server/plugin.ts", @@ -1529,13 +1517,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", plugins: ", "SecuritySolutionPluginStartDependencies", ") => ", @@ -1559,13 +1541,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "x-pack/plugins/security_solution/server/plugin.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 4e5ff0dadf522..2e8307de6f176 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index f45383da8ab4b..5907661a277f4 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2022-10-25 +date: 2022-10-27 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 4b5d3116ae1f2..181f7915dd280 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2022-10-25 +date: 2022-10-27 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 381ded84be657..3961744180e2e 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2022-10-25 +date: 2022-10-27 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 3082e647ec073..a88d0c575f4b4 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2022-10-25 +date: 2022-10-27 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 895b95cabf174..66faad2e7bdb8 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2022-10-25 +date: 2022-10-27 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 092dc001056d1..b2a40c81f24f2 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.devdocs.json b/api_docs/task_manager.devdocs.json index 41d8c4273d8de..cdc661b92a91b 100644 --- a/api_docs/task_manager.devdocs.json +++ b/api_docs/task_manager.devdocs.json @@ -26,13 +26,7 @@ "text": "TaskManagerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "taskManager", @@ -77,13 +71,7 @@ "label": "initContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", @@ -103,13 +91,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", plugins: { usageCollection?: ", { "pluginId": "usageCollection", @@ -139,13 +121,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", @@ -199,13 +175,7 @@ "description": [], "signature": [ "({ savedObjects, elasticsearch, executionContext, }: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ") => ", { "pluginId": "taskManager", @@ -227,13 +197,7 @@ "label": "{\n savedObjects,\n elasticsearch,\n executionContext,\n }", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", "deprecated": false, @@ -1534,7 +1498,9 @@ "TaskScheduling", ", \"schedule\" | \"runSoon\" | \"ephemeralRunNow\" | \"ensureScheduled\" | \"bulkUpdateSchedules\" | \"bulkEnable\" | \"bulkDisable\" | \"bulkSchedule\"> & Pick<", "TaskStore", - ", \"get\" | \"aggregate\" | \"fetch\" | \"remove\"> & { removeIfExists: (id: string) => Promise; } & { supportsEphemeralTasks: () => boolean; }" + ", \"get\" | \"aggregate\" | \"fetch\" | \"remove\"> & { removeIfExists: (id: string) => Promise; } & { bulkRemoveIfExist: (ids: string[]) => Promise<", + "SavedObjectsBulkDeleteResponse", + " | undefined>; } & { supportsEphemeralTasks: () => boolean; }" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", "deprecated": false, diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 843204fcaf20d..4a2f037a62908 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2022-10-25 +date: 2022-10-27 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 e6edb2ed36b3d..375b8a20ddb6c 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2022-10-25 +date: 2022-10-27 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 7632ff82b879d..5c665aa41c8d1 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2022-10-25 +date: 2022-10-27 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 c6a6c1d91453d..cb364a70043b7 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2022-10-25 +date: 2022-10-27 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 7370b16670876..6a2b6cbdb3f10 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 683cd251430b3..bf513d9715539 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index e31dc72c8f573..bf9379ef8b081 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2022-10-25 +date: 2022-10-27 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 071fee2d58cd1..95f51743910c5 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 252ab38f8c885..6de961837296f 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 9c16586e54ca2..71ab21795d1e3 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.devdocs.json b/api_docs/ui_actions_enhanced.devdocs.json index 7d029f3b88c45..fb7773659555d 100644 --- a/api_docs/ui_actions_enhanced.devdocs.json +++ b/api_docs/ui_actions_enhanced.devdocs.json @@ -3656,13 +3656,7 @@ "text": "AdvancedUiActionsServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "uiActionsEnhanced", @@ -3732,13 +3726,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", ", { embeddable }: SetupDependencies) => { registerActionFactory: (definition: ", { "pluginId": "uiActionsEnhanced", @@ -3769,13 +3757,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "" ], "path": "src/plugins/ui_actions_enhanced/server/plugin.ts", diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 2bfb0f9c70e8d..d583e50ce35df 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2022-10-25 +date: 2022-10-27 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 7df784517d3e4..c6cd331100e2f 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: 2022-10-25 +date: 2022-10-27 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 e79c1a6d367e7..9307ca4f2e23f 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: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index ea8e01217ba92..4ee81970fe4c7 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -1904,13 +1904,7 @@ "text": "UnifiedSearchServerPlugin" }, " implements ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.Plugin", - "text": "Plugin" - }, + "Plugin", "<", { "pluginId": "unifiedSearch", @@ -1947,13 +1941,7 @@ "label": "initializerContext", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, + "PluginInitializerContext", "; valueSuggestions: Readonly<{} & { timeout: moment.Duration; enabled: boolean; tiers: string[]; terminateAfter: moment.Duration; }>; }>; }>>" ], "path": "src/plugins/unified_search/server/plugin.ts", @@ -1973,13 +1961,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "UnifiedSearchServerPluginStartDependencies", ", ", @@ -2006,13 +1988,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, + "CoreSetup", "<", "UnifiedSearchServerPluginStartDependencies", ", ", @@ -2057,13 +2033,7 @@ "description": [], "signature": [ "(core: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, + "CoreStart", ", {}: ", "UnifiedSearchServerPluginStartDependencies", ") => {}" @@ -2080,13 +2050,7 @@ "label": "core", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } + "CoreStart" ], "path": "src/plugins/unified_search/server/plugin.ts", "deprecated": false, diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 412a8fcded594..c30024c987f18 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2022-10-25 +date: 2022-10-27 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 ce677b719e0de..4cdf0604fce49 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2022-10-25 +date: 2022-10-27 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 389c2112f5370..2b7f8f4c348c7 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2022-10-25 +date: 2022-10-27 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 312a5be4a7976..dff18eb622be0 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2022-10-25 +date: 2022-10-27 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 b84b7d7047872..5f068af205279 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2022-10-25 +date: 2022-10-27 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 5d88263723e81..ed04d200d187b 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2022-10-25 +date: 2022-10-27 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 519a613103e82..b691fbc749e23 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2022-10-25 +date: 2022-10-27 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 1fd3c29d65a7e..c3f84534fac5c 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2022-10-25 +date: 2022-10-27 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 7986a2253f552..090136b4acb74 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2022-10-25 +date: 2022-10-27 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 c7432e566dede..5e466bb97f00d 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2022-10-25 +date: 2022-10-27 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 d6effa9d63185..d6931853fad20 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2022-10-25 +date: 2022-10-27 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 3d47ee7ff0dfa..20ed2a608f2e5 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2022-10-25 +date: 2022-10-27 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 d0447b0e254e3..76e49206309f3 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2022-10-25 +date: 2022-10-27 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 8c4105f7fca02..a9de284f9266e 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2022-10-25 +date: 2022-10-27 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 fc0bcc1922de2..482291d6a57ce 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index b4c5d22ea35e2..fdf936320467b 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -8472,6 +8472,23 @@ "path": "src/plugins/visualizations/common/convert_to_lens/types/configurations.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "visualizations", + "id": "def-common.ColumnState.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + "PaletteOutput", + "<", + "CustomPaletteParams", + "> | undefined" + ], + "path": "src/plugins/visualizations/common/convert_to_lens/types/configurations.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 075aa9e609598..ee708b91ea6b8 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2022-10-25 +date: 2022-10-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 759 | 12 | 729 | 18 | +| 760 | 12 | 730 | 18 | ## Client diff --git a/docs/index-custom-title-page.html b/docs/index-custom-title-page.html new file mode 100644 index 0000000000000..86fd3a16b3bb3 --- /dev/null +++ b/docs/index-custom-title-page.html @@ -0,0 +1,254 @@ + + +
+ +
+
+

+

Bring your data to life

+

+ Kibana is a user interface that lets you visualize your Elasticsearch data and navigate the Elastic Stack. + Take this tutorial for the basics of visualizing data. +

+

+ + + +

+

+ What's new + Release notes + How-to videos +

+
+
+ +
+
+ +

Explore by use case

+ + + +

Get to know Kibana

+ + + + + +
+
+

+ + Manage and secure +

+
+ +
+ +
+
+

+ + Install and upgrade +

+
+ +
+ +
+
+

+ + Tools, APIs, and Dev docs +

+
+ +
+ + +

View all Elastic docs

diff --git a/docs/index-extra-title-page.html b/docs/index-extra-title-page.html deleted file mode 100644 index ced2737984fa5..0000000000000 --- a/docs/index-extra-title-page.html +++ /dev/null @@ -1,153 +0,0 @@ -
-

- From creating beautiful visualizations to managing the Elastic Stack, learn how Kibana helps you - get the most of your data. -

-

- What's new - Release notes - How-to videos -

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

New to Kibana?

Popular topics

- - - -

Analyze your data

Manage all things Stack

- - - -
- -

All topics

-
diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc index aa747611bdbaa..8575d9fda01ed 100644 --- a/docs/maps/search.asciidoc +++ b/docs/maps/search.asciidoc @@ -107,7 +107,7 @@ You can create spatial filters in two ways: Spatial filters have the following properties: * *Geometry label* enables you to provide a meaningful name for your spatial filter. -* *Spatial relation* determines the {ref}/query-dsl-geo-shape-query.html#_spatial_relations[spatial relation operator] to use at search time. +* *Spatial relation* determines the {ref}/query-dsl-geo-shape-query.html#geo-shape-spatial-relations[spatial relation operator] to use at search time. * *Action* specifies whether to apply the filter to the current view or to a drilldown action. Only available when the map is a panel in a {kibana-ref}/dashboard.html[dashboard] with {kibana-ref}/drilldowns.html[drilldowns]. [role="screenshot"] diff --git a/nav-kibana-dev.docnav.json b/nav-kibana-dev.docnav.json index 14e27632c33f4..8b49d43be942a 100644 --- a/nav-kibana-dev.docnav.json +++ b/nav-kibana-dev.docnav.json @@ -106,6 +106,10 @@ }, { "id": "kibDevDocsEmbeddables" + }, + { + "id": "kibCloudExperimentsPlugin", + "label": "A/B testing on Elastic Cloud" } ] }, diff --git a/package.json b/package.json index 909f468342b82..bb7cd79238c33 100644 --- a/package.json +++ b/package.json @@ -241,6 +241,9 @@ "@kbn/core-lifecycle-browser": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser", "@kbn/core-lifecycle-browser-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal", "@kbn/core-lifecycle-browser-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks", + "@kbn/core-lifecycle-server": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server", + "@kbn/core-lifecycle-server-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-internal", + "@kbn/core-lifecycle-server-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-mocks", "@kbn/core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server", "@kbn/core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal", "@kbn/core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks", @@ -264,6 +267,9 @@ "@kbn/core-plugins-browser": "link:bazel-bin/packages/core/plugins/core-plugins-browser", "@kbn/core-plugins-browser-internal": "link:bazel-bin/packages/core/plugins/core-plugins-browser-internal", "@kbn/core-plugins-browser-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks", + "@kbn/core-plugins-server": "link:bazel-bin/packages/core/plugins/core-plugins-server", + "@kbn/core-plugins-server-internal": "link:bazel-bin/packages/core/plugins/core-plugins-server-internal", + "@kbn/core-plugins-server-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-server-mocks", "@kbn/core-preboot-server": "link:bazel-bin/packages/core/preboot/core-preboot-server", "@kbn/core-preboot-server-internal": "link:bazel-bin/packages/core/preboot/core-preboot-server-internal", "@kbn/core-preboot-server-mocks": "link:bazel-bin/packages/core/preboot/core-preboot-server-mocks", @@ -509,8 +515,8 @@ "he": "^1.2.0", "history": "^4.9.0", "hjson": "3.2.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^5.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", "i18n-iso-countries": "^4.3.1", "icalendar": "0.7.1", "immer": "^9.0.15", @@ -593,7 +599,7 @@ "react-fast-compare": "^2.0.4", "react-focus-on": "^3.6.0", "react-grid-layout": "^1.3.4", - "react-hook-form": "^7.37.0", + "react-hook-form": "^7.38.0", "react-intl": "^2.8.0", "react-is": "^17.0.2", "react-markdown": "^6.0.3", @@ -666,7 +672,7 @@ "vinyl": "^2.2.0", "whatwg-fetch": "^3.0.0", "xml2js": "^0.4.22", - "xterm": "^4.18.0", + "xterm": "^5.0.0", "yauzl": "^2.10.0", "yazl": "^2.5.1" }, @@ -705,9 +711,9 @@ "@emotion/jest": "^11.10.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@istanbuljs/schema": "^0.1.2", - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/types": "^26", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/types": "^27", "@kbn/ambient-storybook-types": "link:bazel-bin/packages/kbn-ambient-storybook-types", "@kbn/ambient-ui-types": "link:bazel-bin/packages/kbn-ambient-ui-types", "@kbn/apm-synthtrace": "link:bazel-bin/packages/kbn-apm-synthtrace", @@ -790,10 +796,10 @@ "@storybook/react-docgen-typescript-plugin": "^1.0.1", "@storybook/testing-react": "^1.3.0", "@storybook/theming": "^6.5.12", - "@testing-library/dom": "^8.12.0", - "@testing-library/jest-dom": "^5.16.3", + "@testing-library/dom": "^8.17.1", + "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^12.1.5", - "@testing-library/react-hooks": "^7.0.2", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^13.5.0", "@types/apidoc": "^0.22.3", "@types/archiver": "^5.3.1", @@ -843,10 +849,9 @@ "@types/history": "^4.7.9", "@types/hjson": "^2.4.2", "@types/http-proxy": "^1.17.4", - "@types/http-proxy-agent": "^2.0.2", "@types/inquirer": "^7.3.1", "@types/intl-relativeformat": "^2.1.0", - "@types/jest": "^26.0.22", + "@types/jest": "^27.4.1", "@types/jest-axe": "^3.5.3", "@types/joi": "^17.2.3", "@types/jquery": "^3.3.31", @@ -980,6 +985,9 @@ "@types/kbn__core-lifecycle-browser": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser/npm_module_types", "@types/kbn__core-lifecycle-browser-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal/npm_module_types", "@types/kbn__core-lifecycle-browser-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks/npm_module_types", + "@types/kbn__core-lifecycle-server": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server/npm_module_types", + "@types/kbn__core-lifecycle-server-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-internal/npm_module_types", + "@types/kbn__core-lifecycle-server-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-mocks/npm_module_types", "@types/kbn__core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server/npm_module_types", "@types/kbn__core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal/npm_module_types", "@types/kbn__core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks/npm_module_types", @@ -1003,6 +1011,9 @@ "@types/kbn__core-plugins-browser": "link:bazel-bin/packages/core/plugins/core-plugins-browser/npm_module_types", "@types/kbn__core-plugins-browser-internal": "link:bazel-bin/packages/core/plugins/core-plugins-browser-internal/npm_module_types", "@types/kbn__core-plugins-browser-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks/npm_module_types", + "@types/kbn__core-plugins-server": "link:bazel-bin/packages/core/plugins/core-plugins-server/npm_module_types", + "@types/kbn__core-plugins-server-internal": "link:bazel-bin/packages/core/plugins/core-plugins-server-internal/npm_module_types", + "@types/kbn__core-plugins-server-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-server-mocks/npm_module_types", "@types/kbn__core-preboot-server": "link:bazel-bin/packages/core/preboot/core-preboot-server/npm_module_types", "@types/kbn__core-preboot-server-internal": "link:bazel-bin/packages/core/preboot/core-preboot-server-internal/npm_module_types", "@types/kbn__core-preboot-server-mocks": "link:bazel-bin/packages/core/preboot/core-preboot-server-mocks/npm_module_types", @@ -1297,7 +1308,7 @@ "argsplit": "^1.0.5", "autoprefixer": "^10.4.7", "axe-core": "^4.0.2", - "babel-jest": "^26.6.3", + "babel-jest": "^27.5.1", "babel-loader": "^8.2.5", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-istanbul": "^6.1.1", @@ -1332,7 +1343,7 @@ "dpdm": "3.5.0", "ejs": "^3.1.8", "enzyme": "^3.11.0", - "enzyme-to-json": "^3.6.1", + "enzyme-to-json": "^3.6.2", "eslint": "^7.32.0", "eslint-config-prettier": "^8.5.0", "eslint-module-utils": "^2.6.2", @@ -1370,21 +1381,21 @@ "html-loader": "^1.3.2", "http-proxy": "^1.18.1", "is-path-inside": "^3.0.2", - "jest": "^26.6.3", + "jest": "^27.5.1", "jest-axe": "^5.0.0", - "jest-canvas-mock": "^2.3.1", - "jest-circus": "^26.6.3", - "jest-cli": "^26.6.3", - "jest-config": "^26", - "jest-diff": "^26.6.2", - "jest-environment-jsdom": "^26.6.2", - "jest-mock": "^26.6.2", + "jest-canvas-mock": "^2.4.0", + "jest-cli": "^27.5.1", + "jest-config": "^27.5.1", + "jest-diff": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-mock": "^27.5.1", "jest-raw-loader": "^1.0.1", - "jest-runtime": "^26", + "jest-runtime": "^27.5.1", "jest-silent-reporter": "^0.5.0", - "jest-snapshot": "^26.6.2", - "jest-specific-snapshot": "^4.0.0", - "jest-styled-components": "^7.0.3", + "jest-snapshot": "^27.5.1", + "jest-specific-snapshot": "^5.0.0", + "jest-styled-components": "7.0.3", "jsdom": "^16.4.0", "json-schema-typed": "^8.0.1", "json5": "^1.0.1", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index b68c27b27f3dd..d14389555251f 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -105,6 +105,9 @@ filegroup( "//packages/core/lifecycle/core-lifecycle-browser:build", "//packages/core/lifecycle/core-lifecycle-browser-internal:build", "//packages/core/lifecycle/core-lifecycle-browser-mocks:build", + "//packages/core/lifecycle/core-lifecycle-server:build", + "//packages/core/lifecycle/core-lifecycle-server-internal:build", + "//packages/core/lifecycle/core-lifecycle-server-mocks:build", "//packages/core/logging/core-logging-server:build", "//packages/core/logging/core-logging-server-internal:build", "//packages/core/logging/core-logging-server-mocks:build", @@ -128,6 +131,9 @@ filegroup( "//packages/core/plugins/core-plugins-browser:build", "//packages/core/plugins/core-plugins-browser-internal:build", "//packages/core/plugins/core-plugins-browser-mocks:build", + "//packages/core/plugins/core-plugins-server:build", + "//packages/core/plugins/core-plugins-server-internal:build", + "//packages/core/plugins/core-plugins-server-mocks:build", "//packages/core/preboot/core-preboot-server:build", "//packages/core/preboot/core-preboot-server-internal:build", "//packages/core/preboot/core-preboot-server-mocks:build", @@ -454,6 +460,9 @@ filegroup( "//packages/core/lifecycle/core-lifecycle-browser:build_types", "//packages/core/lifecycle/core-lifecycle-browser-internal:build_types", "//packages/core/lifecycle/core-lifecycle-browser-mocks:build_types", + "//packages/core/lifecycle/core-lifecycle-server:build_types", + "//packages/core/lifecycle/core-lifecycle-server-internal:build_types", + "//packages/core/lifecycle/core-lifecycle-server-mocks:build_types", "//packages/core/logging/core-logging-server:build_types", "//packages/core/logging/core-logging-server-internal:build_types", "//packages/core/logging/core-logging-server-mocks:build_types", @@ -477,6 +486,9 @@ filegroup( "//packages/core/plugins/core-plugins-browser:build_types", "//packages/core/plugins/core-plugins-browser-internal:build_types", "//packages/core/plugins/core-plugins-browser-mocks:build_types", + "//packages/core/plugins/core-plugins-server:build_types", + "//packages/core/plugins/core-plugins-server-internal:build_types", + "//packages/core/plugins/core-plugins-server-mocks:build_types", "//packages/core/preboot/core-preboot-server:build_types", "//packages/core/preboot/core-preboot-server-internal:build_types", "//packages/core/preboot/core-preboot-server-mocks:build_types", diff --git a/packages/analytics/client/src/analytics_client/analytics_client.test.ts b/packages/analytics/client/src/analytics_client/analytics_client.test.ts index a53489e312083..601f94aa1e243 100644 --- a/packages/analytics/client/src/analytics_client/analytics_client.test.ts +++ b/packages/analytics/client/src/analytics_client/analytics_client.test.ts @@ -21,7 +21,7 @@ describe('AnalyticsClient', () => { let logger: MockedLogger; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); logger = loggerMock.create(); analyticsClient = new AnalyticsClient({ logger, diff --git a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts b/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts index fae3121372193..47728a99a511a 100644 --- a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts +++ b/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts @@ -33,7 +33,7 @@ describe('ElasticV3BrowserShipper', () => { let fetchMock: jest.Mock; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); fetchMock = jest.fn().mockResolvedValue({ status: 200, diff --git a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts b/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts index 03356f7428da7..091be6cb96e83 100644 --- a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts +++ b/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts @@ -40,7 +40,7 @@ describe('ElasticV3ServerShipper', () => { const setLastBatchSent = (ms: number) => (shipper['lastBatchSent'] = ms); beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); shipper = new ElasticV3ServerShipper( { version: '1.2.3', channelName: 'test-channel', debug: true }, diff --git a/packages/content-management/table_list/src/table_list_view.test.tsx b/packages/content-management/table_list/src/table_list_view.test.tsx index 8e5aff4ae0dbe..01b1a3b215ea1 100644 --- a/packages/content-management/table_list/src/table_list_view.test.tsx +++ b/packages/content-management/table_list/src/table_list_view.test.tsx @@ -49,7 +49,7 @@ const requiredProps: TableListViewProps = { describe('TableListView', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts index d3514cb80edf3..177a01393a3e2 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts @@ -12,6 +12,18 @@ import { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser import { analyticsClientMock } from './analytics_service.test.mocks'; import { AnalyticsService } from './analytics_service'; +function findRegisteredContextProviderByName(contextProviderName: string) { + return analyticsClientMock.registerContextProvider.mock.calls.find( + ([{ name }]) => name === contextProviderName + )!; +} + +function findRegisteredEventTypeByName(eventTypeName: string) { + return analyticsClientMock.registerEventType.mock.calls.find( + ([{ eventType }]) => eventType === eventTypeName + )!; +} + describe('AnalyticsService', () => { let analyticsService: AnalyticsService; beforeEach(() => { @@ -19,34 +31,39 @@ describe('AnalyticsService', () => { analyticsService = new AnalyticsService(coreContextMock.create()); }); test('should register some context providers on creation', async () => { - expect(analyticsClientMock.registerContextProvider).toHaveBeenCalledTimes(3); - expect( - await firstValueFrom(analyticsClientMock.registerContextProvider.mock.calls[0][0].context$) - ).toMatchInlineSnapshot(` - Object { - "branch": "branch", - "buildNum": 100, - "buildSha": "buildSha", - "isDev": true, - "isDistributable": false, - "version": "version", - } - `); + expect(analyticsClientMock.registerContextProvider).toHaveBeenCalledTimes(4); + expect(await firstValueFrom(findRegisteredContextProviderByName('build info')[0].context$)) + .toMatchInlineSnapshot(` + Object { + "branch": "branch", + "buildNum": 100, + "buildSha": "buildSha", + "isDev": true, + "isDistributable": false, + "version": "version", + } + `); expect( - await firstValueFrom(analyticsClientMock.registerContextProvider.mock.calls[1][0].context$) + await firstValueFrom(findRegisteredContextProviderByName('session-id')[0].context$) ).toEqual({ session_id: expect.any(String) }); expect( - await firstValueFrom(analyticsClientMock.registerContextProvider.mock.calls[2][0].context$) + await firstValueFrom(findRegisteredContextProviderByName('browser info')[0].context$) ).toEqual({ preferred_language: 'en-US', preferred_languages: ['en-US', 'en'], user_agent: expect.any(String), }); + expect( + await firstValueFrom(findRegisteredContextProviderByName('viewport_size')[0].context$) + ).toEqual({ + viewport_width: 1024, + viewport_height: 768, + }); }); test('should register the `performance_metric` and `click` event types on creation', () => { - expect(analyticsClientMock.registerEventType).toHaveBeenCalledTimes(2); - expect(analyticsClientMock.registerEventType.mock.calls[0]).toMatchInlineSnapshot(` + expect(analyticsClientMock.registerEventType).toHaveBeenCalledTimes(3); + expect(findRegisteredEventTypeByName('performance_metric')).toMatchInlineSnapshot(` Array [ Object { "eventType": "performance_metric", @@ -144,7 +161,7 @@ describe('AnalyticsService', () => { }, ] `); - expect(analyticsClientMock.registerEventType.mock.calls[1]).toMatchInlineSnapshot(` + expect(findRegisteredEventTypeByName('click')).toMatchInlineSnapshot(` Array [ Object { "eventType": "click", @@ -162,6 +179,27 @@ describe('AnalyticsService', () => { }, ] `); + expect(findRegisteredEventTypeByName('viewport_resize')).toMatchInlineSnapshot(` + Array [ + Object { + "eventType": "viewport_resize", + "schema": Object { + "viewport_height": Object { + "_meta": Object { + "description": "The value seen as the CSS viewport @media (height)", + }, + "type": "long", + }, + "viewport_width": Object { + "_meta": Object { + "description": "The value seen as the CSS viewport @media (width)", + }, + "type": "long", + }, + }, + }, + ] + `); }); test('setup should expose all the register APIs, reportEvent and opt-in', () => { @@ -181,7 +219,7 @@ describe('AnalyticsService', () => { const injectedMetadata = injectedMetadataServiceMock.createSetupContract(); analyticsService.setup({ injectedMetadata }); expect( - await firstValueFrom(analyticsClientMock.registerContextProvider.mock.calls[3][0].context$) + await firstValueFrom(findRegisteredContextProviderByName('elasticsearch info')[0].context$) ).toMatchInlineSnapshot(`undefined`); }); @@ -194,14 +232,14 @@ describe('AnalyticsService', () => { }); analyticsService.setup({ injectedMetadata }); expect( - await firstValueFrom(analyticsClientMock.registerContextProvider.mock.calls[3][0].context$) + await firstValueFrom(findRegisteredContextProviderByName('elasticsearch info')[0].context$) ).toMatchInlineSnapshot(` - Object { - "cluster_name": "cluster_name", - "cluster_uuid": "cluster_uuid", - "cluster_version": "version", - } - `); + Object { + "cluster_name": "cluster_name", + "cluster_uuid": "cluster_uuid", + "cluster_version": "version", + } + `); }); test('setup should expose only the APIs report and opt-in', () => { diff --git a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts index 938b0b043bc29..0dcd49bd69fcc 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { of } from 'rxjs'; +import { of, Subscription } from 'rxjs'; import type { AnalyticsClient } from '@kbn/analytics-client'; import { createAnalytics } from '@kbn/analytics-client'; import { registerPerformanceMetricEventType } from '@kbn/ebt-tools'; @@ -16,6 +16,7 @@ import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-ana import { trackClicks } from './track_clicks'; import { getSessionId } from './get_session_id'; import { createLogger } from './logger'; +import { trackViewportSize } from './track_viewport_size'; /** @internal */ export interface AnalyticsServiceSetupDeps { @@ -24,6 +25,7 @@ export interface AnalyticsServiceSetupDeps { export class AnalyticsService { private readonly analyticsClient: AnalyticsClient; + private readonly subscriptionsHandler = new Subscription(); constructor(core: CoreContext) { this.analyticsClient = createAnalytics({ @@ -41,7 +43,8 @@ export class AnalyticsService { // and can benefit other consumers of the client. this.registerSessionIdContext(); this.registerBrowserInfoAnalyticsContext(); - trackClicks(this.analyticsClient, core.env.mode.dev); + this.subscriptionsHandler.add(trackClicks(this.analyticsClient, core.env.mode.dev)); + this.subscriptionsHandler.add(trackViewportSize(this.analyticsClient)); } public setup({ injectedMetadata }: AnalyticsServiceSetupDeps): AnalyticsServiceSetup { @@ -67,6 +70,7 @@ export class AnalyticsService { } public stop() { + this.subscriptionsHandler.unsubscribe(); this.analyticsClient.shutdown(); } diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts new file mode 100644 index 0000000000000..f99d6681e5ad8 --- /dev/null +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts @@ -0,0 +1,77 @@ +/* + * Copyright 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 { firstValueFrom, take, type Subscription, toArray } from 'rxjs'; +import { analyticsClientMock } from './analytics_service.test.mocks'; +import { trackViewportSize } from './track_viewport_size'; + +describe('trackViewportSize', () => { + const addEventListenerSpy = jest.spyOn(window, 'addEventListener'); + let subscription: Subscription | undefined; + + afterEach(() => { + subscription?.unsubscribe(); + jest.resetAllMocks(); + }); + + test('registers the analytics event type, the context provider, and a listener to the "resize" events', () => { + subscription = trackViewportSize(analyticsClientMock); + + expect(analyticsClientMock.registerContextProvider).toHaveBeenCalledTimes(1); + expect(analyticsClientMock.registerContextProvider).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'viewport_size', + }) + ); + + expect(analyticsClientMock.registerEventType).toHaveBeenCalledTimes(1); + expect(analyticsClientMock.registerEventType).toHaveBeenCalledWith( + expect.objectContaining({ + eventType: 'viewport_resize', + }) + ); + expect(addEventListenerSpy).toHaveBeenCalledTimes(1); + expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function), undefined); + }); + + test('emits a context update before the resize occurs', async () => { + subscription = trackViewportSize(analyticsClientMock); + + const { context$ } = analyticsClientMock.registerContextProvider.mock.calls[0][0]; + await expect(firstValueFrom(context$.pipe(take(1)))).resolves.toStrictEqual({ + viewport_width: 1024, + viewport_height: 768, + }); + }); + + test('reports an analytics event when a resize event occurs', async () => { + subscription = trackViewportSize(analyticsClientMock); + + const { context$ } = analyticsClientMock.registerContextProvider.mock.calls[0][0]; + + // window.resizeTo(100, 100) wouldn't trigger the event in Jest, so we need to call the listener straight away. + // eslint-disable-next-line dot-notation + window['innerWidth'] = 100; + // eslint-disable-next-line dot-notation + window['innerHeight'] = 100; + + expect(addEventListenerSpy).toHaveBeenCalledTimes(1); + (addEventListenerSpy.mock.calls[0][1] as Function)(); + + await expect(firstValueFrom(context$.pipe(take(2), toArray()))).resolves.toStrictEqual([ + { viewport_width: 1024, viewport_height: 768 }, + { viewport_width: 100, viewport_height: 100 }, + ]); + + expect(analyticsClientMock.reportEvent).toHaveBeenCalledTimes(1); + expect(analyticsClientMock.reportEvent).toHaveBeenCalledWith('viewport_resize', { + viewport_width: 100, + viewport_height: 100, + }); + }); +}); diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts new file mode 100644 index 0000000000000..17fab459f2e8f --- /dev/null +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts @@ -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 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 { debounceTime, fromEvent, map, merge, of, shareReplay } from 'rxjs'; +import type { AnalyticsClient, RootSchema } from '@kbn/analytics-client'; + +export interface ViewportSize { + viewport_width: number; + viewport_height: number; +} + +const schema: RootSchema = { + viewport_width: { + type: 'long', + _meta: { description: 'The value seen as the CSS viewport @media (width)' }, + }, + viewport_height: { + type: 'long', + _meta: { description: 'The value seen as the CSS viewport @media (height)' }, + }, +}; + +/** + * Get the @media (width) and @media (height) in the format of {@link ViewportSize} + */ +function getViewportSize(): ViewportSize { + // Explanation of the math below: https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions + return { + viewport_width: Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0), + viewport_height: Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0), + }; +} + +/** + * Registers the event type "viewport_size" in the analytics client, and the context provider with the same name. + * Then it listens to all the "resize" events in the UI and reports their size as {@link ViewportSize} + * @param analytics + */ +export function trackViewportSize(analytics: AnalyticsClient) { + // window or document? + // According to MDN, it only emits on `window`: https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event + const resize$ = fromEvent(window, 'resize').pipe( + debounceTime(200), + map(() => getViewportSize()), + shareReplay(1) + ); + + analytics.registerEventType({ + eventType: 'viewport_resize', + schema, + }); + + analytics.registerContextProvider({ + name: 'viewport_size', + schema, + context$: merge( + of(getViewportSize()), // Emits an initial value so initial events' context is also populated + resize$ + ), + }); + + return resize$.subscribe((event) => analytics.reportEvent('viewport_resize', event)); +} diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 3c4b42cddfae7..f039fb7c24740 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -23,6 +23,7 @@ import type { ChromeBadge, ChromeBreadcrumb, ChromeBreadcrumbsAppendExtension, + ChromeGlobalHelpExtensionMenuLink, ChromeHelpExtension, ChromeUserBanner, } from '@kbn/core-chrome-browser'; @@ -103,6 +104,9 @@ export class ChromeService { }: StartDeps): Promise { this.initVisibility(application); + const globalHelpExtensionMenuLinks$ = new BehaviorSubject( + [] + ); const helpExtension$ = new BehaviorSubject(undefined); const breadcrumbs$ = new BehaviorSubject([]); const breadcrumbsAppendExtension$ = new BehaviorSubject< @@ -213,6 +217,7 @@ export class ChromeService { customNavLink$={customNavLink$.pipe(takeUntil(this.stop$))} kibanaDocLink={docLinks.links.kibana.guide} forceAppSwitcherNavigation$={navLinks.getForceAppSwitcherNavigation$()} + globalHelpExtensionMenuLinks$={globalHelpExtensionMenuLinks$} helpExtension$={helpExtension$.pipe(takeUntil(this.stop$))} helpSupportUrl$={helpSupportUrl$.pipe(takeUntil(this.stop$))} homeHref={http.basePath.prepend('/app/home')} @@ -253,6 +258,17 @@ export class ChromeService { breadcrumbsAppendExtension$.next(breadcrumbsAppendExtension); }, + getGlobalHelpExtensionMenuLinks$: () => globalHelpExtensionMenuLinks$.asObservable(), + + registerGlobalHelpExtensionMenuLink: ( + globalHelpExtensionMenuLink: ChromeGlobalHelpExtensionMenuLink + ) => { + globalHelpExtensionMenuLinks$.next([ + ...globalHelpExtensionMenuLinks$.value, + globalHelpExtensionMenuLink, + ]); + }, + getHelpExtension$: () => helpExtension$.pipe(takeUntil(this.stop$)), setHelpExtension: (helpExtension?: ChromeHelpExtension) => { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.test.tsx index 58ac26174f205..02fcce82d2c80 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.test.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.test.tsx @@ -33,6 +33,7 @@ function mockProps() { customNavLink$: new BehaviorSubject(undefined), recentlyAccessed$: new BehaviorSubject([]), forceAppSwitcherNavigation$: new BehaviorSubject(false), + globalHelpExtensionMenuLinks$: new BehaviorSubject([]), helpExtension$: new BehaviorSubject(undefined), helpSupportUrl$: new BehaviorSubject(''), navControlsLeft$: new BehaviorSubject([]), diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.tsx index 5ff0989f16485..cfc79f2779a24 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header.tsx @@ -32,6 +32,7 @@ import type { ChromeRecentlyAccessedHistoryItem, ChromeBreadcrumbsAppendExtension, ChromeHelpExtension, + ChromeGlobalHelpExtensionMenuLink, ChromeUserBanner, } from '@kbn/core-chrome-browser'; import { LoadingIndicator } from '../loading_indicator'; @@ -60,6 +61,7 @@ export interface HeaderProps { navLinks$: Observable; recentlyAccessed$: Observable; forceAppSwitcherNavigation$: Observable; + globalHelpExtensionMenuLinks$: Observable; helpExtension$: Observable; helpSupportUrl$: Observable; navControlsLeft$: Observable; @@ -80,6 +82,7 @@ export function Header({ onIsLockedUpdate, homeHref, breadcrumbsAppendExtension$, + globalHelpExtensionMenuLinks$, ...observables }: HeaderProps) { const isVisible = useObservable(observables.isVisible$, false); @@ -145,6 +148,7 @@ export function Header({ , { + test('it only renders the default content', () => { + const application = applicationServiceMock.createInternalStartContract(); + const helpExtension$ = new BehaviorSubject(undefined); + const helpSupportUrl$ = new BehaviorSubject(''); + + const component = mountWithIntl( + + ); + + expect(component.find('EuiButtonEmpty').length).toBe(1); // only the toggle view on/off button + component.find('EuiButtonEmpty').simulate('click'); + + // 4 default links + the toggle button + expect(component.find('EuiButtonEmpty').length).toBe(5); + }); + + test('it renders the global custom content + the default content', () => { + const application = applicationServiceMock.createInternalStartContract(); + const helpExtension$ = new BehaviorSubject(undefined); + const helpSupportUrl$ = new BehaviorSubject(''); + + const component = mountWithIntl( + + ); + + expect(component.find('EuiButtonEmpty').length).toBe(1); // only the toggle view on/off button + component.find('EuiButtonEmpty').simulate('click'); + + // 2 custom global link + 4 default links + the toggle button + expect(component.find('EuiButtonEmpty').length).toBe(7); + + expect(component.find('[data-test-subj="my-test-custom-link"]').exists()).toBeTruthy(); + + // The first global component is the second button (first is the toggle button) + expect(component.find('EuiButtonEmpty').at(1).prop('data-test-subj')).toBe( + 'my-test-custom-link' + ); + }); +}); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx index 4e797df335543..f938608091ba6 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx @@ -25,13 +25,17 @@ import { } from '@elastic/eui'; import type { InternalApplicationStart } from '@kbn/core-application-browser-internal'; -import type { ChromeHelpExtension } from '@kbn/core-chrome-browser'; +import type { + ChromeHelpExtension, + ChromeGlobalHelpExtensionMenuLink, +} from '@kbn/core-chrome-browser'; import { GITHUB_CREATE_ISSUE_LINK, KIBANA_FEEDBACK_LINK } from '../../constants'; import { HeaderExtension } from './header_extension'; import { isModifiedOrPrevented } from './nav_link'; interface Props { navigateToUrl: InternalApplicationStart['navigateToUrl']; + globalHelpExtensionMenuLinks$: Observable; helpExtension$: Observable; helpSupportUrl$: Observable; kibanaVersion: string; @@ -42,6 +46,7 @@ interface State { isOpen: boolean; helpExtension?: ChromeHelpExtension; helpSupportUrl: string; + globalHelpExtensionMenuLinks: ChromeGlobalHelpExtensionMenuLink[]; } export class HeaderHelpMenu extends Component { @@ -54,17 +59,20 @@ export class HeaderHelpMenu extends Component { isOpen: false, helpExtension: undefined, helpSupportUrl: '', + globalHelpExtensionMenuLinks: [], }; } public componentDidMount() { this.subscription = combineLatest( this.props.helpExtension$, - this.props.helpSupportUrl$ - ).subscribe(([helpExtension, helpSupportUrl]) => { + this.props.helpSupportUrl$, + this.props.globalHelpExtensionMenuLinks$ + ).subscribe(([helpExtension, helpSupportUrl, globalHelpExtensionMenuLinks]) => { this.setState({ helpExtension, helpSupportUrl, + globalHelpExtensionMenuLinks, }); }); } @@ -80,6 +88,7 @@ export class HeaderHelpMenu extends Component { const { kibanaVersion } = this.props; const defaultContent = this.renderDefaultContent(); + const globalCustomContent = this.renderGlobalCustomContent(); const customContent = this.renderCustomContent(); const button = ( @@ -126,8 +135,9 @@ export class HeaderHelpMenu extends Component {
+ {globalCustomContent} {defaultContent} - {defaultContent && customContent && } + {(defaultContent || customContent) && } {customContent}
@@ -183,6 +193,22 @@ export class HeaderHelpMenu extends Component { ); } + private renderGlobalCustomContent() { + const { navigateToUrl } = this.props; + const { globalHelpExtensionMenuLinks } = this.state; + + return globalHelpExtensionMenuLinks + .sort((a, b) => b.priority - a.priority) + .map((link, index) => { + const { linkType, content: text, href, ...rest } = link; + return createCustomLink(index, text, true, { + href, + onClick: this.createOnClickHandler(href, navigateToUrl), + ...rest, + }); + }); + } + private renderCustomContent() { const { helpExtension } = this.state; if (!helpExtension) { diff --git a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts index fc2a48f1329d4..2f5c4deb1f38d 100644 --- a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts +++ b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts @@ -50,6 +50,8 @@ const createStartContractMock = () => { setBreadcrumbs: jest.fn(), getBreadcrumbsAppendExtension$: jest.fn(), setBreadcrumbsAppendExtension: jest.fn(), + getGlobalHelpExtensionMenuLinks$: jest.fn(), + registerGlobalHelpExtensionMenuLink: jest.fn(), getHelpExtension$: jest.fn(), setHelpExtension: jest.fn(), setHelpSupportUrl: jest.fn(), @@ -66,6 +68,7 @@ const createStartContractMock = () => { startContract.getBreadcrumbs$.mockReturnValue(new BehaviorSubject([{} as ChromeBreadcrumb])); startContract.getBreadcrumbsAppendExtension$.mockReturnValue(new BehaviorSubject(undefined)); startContract.getCustomNavLink$.mockReturnValue(new BehaviorSubject(undefined)); + startContract.getGlobalHelpExtensionMenuLinks$.mockReturnValue(new BehaviorSubject([])); startContract.getHelpExtension$.mockReturnValue(new BehaviorSubject(undefined)); startContract.getIsNavDrawerLocked$.mockReturnValue(new BehaviorSubject(false)); startContract.getBodyClasses$.mockReturnValue(new BehaviorSubject([])); diff --git a/packages/core/chrome/core-chrome-browser/index.ts b/packages/core/chrome/core-chrome-browser/index.ts index 16f0134afb7bb..3fbef34126a4a 100644 --- a/packages/core/chrome/core-chrome-browser/index.ts +++ b/packages/core/chrome/core-chrome-browser/index.ts @@ -23,6 +23,7 @@ export type { ChromeHelpExtensionMenuDocumentationLink, ChromeHelpExtensionMenuDiscussLink, ChromeHelpExtensionMenuCustomLink, + ChromeGlobalHelpExtensionMenuLink, ChromeDocTitle, ChromeStart, ChromeRecentlyAccessed, diff --git a/packages/core/chrome/core-chrome-browser/src/contracts.ts b/packages/core/chrome/core-chrome-browser/src/contracts.ts index e3a4f09c2cbb7..a81d9c3c6338f 100644 --- a/packages/core/chrome/core-chrome-browser/src/contracts.ts +++ b/packages/core/chrome/core-chrome-browser/src/contracts.ts @@ -14,6 +14,7 @@ import type { ChromeNavControls } from './nav_controls'; import type { ChromeHelpExtension } from './help_extension'; import type { ChromeBreadcrumb, ChromeBreadcrumbsAppendExtension } from './breadcrumb'; import type { ChromeBadge, ChromeUserBanner } from './types'; +import { ChromeGlobalHelpExtensionMenuLink } from './help_extension'; /** * ChromeStart allows plugins to customize the global chrome header UI and @@ -106,7 +107,19 @@ export interface ChromeStart { setCustomNavLink(newCustomNavLink?: Partial): void; /** - * Get an observable of the current custom help conttent + * Get the list of the registered global help extension menu links + */ + getGlobalHelpExtensionMenuLinks$(): Observable; + + /** + * Append a global help extension menu link + */ + registerGlobalHelpExtensionMenuLink( + globalHelpExtensionMenuLink: ChromeGlobalHelpExtensionMenuLink + ): void; + + /** + * Get an observable of the current custom help content */ getHelpExtension$(): Observable; diff --git a/packages/core/chrome/core-chrome-browser/src/help_extension.ts b/packages/core/chrome/core-chrome-browser/src/help_extension.ts index 3acebd168f49a..f682a166ca29c 100644 --- a/packages/core/chrome/core-chrome-browser/src/help_extension.ts +++ b/packages/core/chrome/core-chrome-browser/src/help_extension.ts @@ -94,6 +94,14 @@ export interface ChromeHelpExtensionMenuCustomLink extends ChromeHelpExtensionLi content: React.ReactNode; } +/** @public */ +export interface ChromeGlobalHelpExtensionMenuLink extends ChromeHelpExtensionMenuCustomLink { + /** + * Highest priority items are listed at the top of the list of links. + */ + priority: number; +} + /** @public */ export type ChromeHelpExtensionMenuLink = | ChromeHelpExtensionMenuGitHubLink diff --git a/packages/core/chrome/core-chrome-browser/src/index.ts b/packages/core/chrome/core-chrome-browser/src/index.ts index 8414de3193c41..716af097fded7 100644 --- a/packages/core/chrome/core-chrome-browser/src/index.ts +++ b/packages/core/chrome/core-chrome-browser/src/index.ts @@ -18,6 +18,7 @@ export type { ChromeHelpExtensionMenuDiscussLink, ChromeHelpExtensionMenuDocumentationLink, ChromeHelpExtensionMenuGitHubLink, + ChromeGlobalHelpExtensionMenuLink, } from './help_extension'; export type { ChromeNavControls, ChromeNavControl } from './nav_controls'; export type { ChromeNavLinks, ChromeNavLink } from './nav_links'; diff --git a/packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts b/packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts index 881efe261d79f..82b4f04410a65 100644 --- a/packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts +++ b/packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts @@ -23,8 +23,10 @@ export const getApmConfig = (requestPath: string) => { return null; } + // Cleanup RUM unsupported attrbiutes from base apm config. + const { contextPropagationOnly, logUncaughtExceptions, ...restOfConfig } = baseConfig; const config: Record = { - ...baseConfig, + ...restOfConfig, pageLoadTransactionName: requestPath, }; diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-server-internal/BUILD.bazel new file mode 100644 index 0000000000000..f09460293560f --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/BUILD.bazel @@ -0,0 +1,125 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-lifecycle-server-internal" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-server-internal" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/logging/core-logging-server-internal:npm_module_types", + "//packages/core/analytics/core-analytics-server:npm_module_types", + "//packages/core/preboot/core-preboot-server-internal:npm_module_types", + "//packages/core/http/core-http-context-server-internal:npm_module_types", + "//packages/core/http/core-http-server-internal:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server-internal:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-server-internal:npm_module_types", + "//packages/core/http/core-http-resources-server-internal:npm_module_types", + "//packages/core/capabilities/core-capabilities-server:npm_module_types", + "//packages/core/doc-links/core-doc-links-server:npm_module_types", + "//packages/core/i18n/core-i18n-server:npm_module_types", + "//packages/core/environment/core-environment-server-internal:npm_module_types", + "//packages/core/execution-context/core-execution-context-server-internal:npm_module_types", + "//packages/core/deprecations/core-deprecations-server-internal:npm_module_types", + "//packages/core/metrics/core-metrics-server-internal:npm_module_types", + "//packages/core/rendering/core-rendering-server-internal:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-server-internal:npm_module_types", + "//packages/core/status/core-status-server-internal:npm_module_types", + "//packages/core/usage-data/core-usage-data-base-server-internal:npm_module_types", + "//packages/core/usage-data/core-usage-data-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/README.md b/packages/core/lifecycle/core-lifecycle-server-internal/README.md new file mode 100644 index 0000000000000..b2eecd8ad21ad --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/README.md @@ -0,0 +1,7 @@ +# @kbn/core-lifecycle-server-internal + + +This package contains the internal types for core's server-side lifecycle contracts: +- `InternalCorePreboot` +- `InternalCoreSetup` +- `InternalCoreStart` diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/index.ts b/packages/core/lifecycle/core-lifecycle-server-internal/index.ts new file mode 100644 index 0000000000000..6c3a41be1b49d --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { InternalCorePreboot, InternalCoreSetup, InternalCoreStart } from './src'; diff --git a/src/core/server/integration_tests/plugins/plugins_service.test.mocks.ts b/packages/core/lifecycle/core-lifecycle-server-internal/jest.config.js similarity index 56% rename from src/core/server/integration_tests/plugins/plugins_service.test.mocks.ts rename to packages/core/lifecycle/core-lifecycle-server-internal/jest.config.js index d20d3bc094ac4..039817196b1fe 100644 --- a/src/core/server/integration_tests/plugins/plugins_service.test.mocks.ts +++ b/packages/core/lifecycle/core-lifecycle-server-internal/jest.config.js @@ -6,13 +6,8 @@ * Side Public License, v 1. */ -export const mockPackage = { - raw: { __dirname: '/tmp' } as any, +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-server-internal'], }; - -jest.doMock('load-json-file', () => ({ - sync: () => mockPackage.raw, -})); - -export const mockDiscover = jest.fn(); -jest.mock('../../plugins/discovery/plugins_discovery', () => ({ discover: mockDiscover })); diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-server-internal/kibana.jsonc new file mode 100644 index 0000000000000..7f8fa2fc8f6ad --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-server-internal", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/package.json b/packages/core/lifecycle/core-lifecycle-server-internal/package.json new file mode 100644 index 0000000000000..9b0c909b58e0e --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-lifecycle-server-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/src/index.ts b/packages/core/lifecycle/core-lifecycle-server-internal/src/index.ts new file mode 100644 index 0000000000000..617706c7d53f9 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/src/index.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { InternalCorePreboot } from './internal_core_preboot'; +export type { InternalCoreSetup } from './internal_core_setup'; +export type { InternalCoreStart } from './internal_core_start'; diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_preboot.ts b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_preboot.ts new file mode 100644 index 0000000000000..18f4c605c1b16 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_preboot.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { InternalLoggingServicePreboot } from '@kbn/core-logging-server-internal'; +import type { AnalyticsServicePreboot } from '@kbn/core-analytics-server'; +import type { InternalPrebootServicePreboot } from '@kbn/core-preboot-server-internal'; +import type { InternalContextPreboot } from '@kbn/core-http-context-server-internal'; +import type { InternalHttpServicePreboot } from '@kbn/core-http-server-internal'; +import type { InternalElasticsearchServicePreboot } from '@kbn/core-elasticsearch-server-internal'; +import type { InternalUiSettingsServicePreboot } from '@kbn/core-ui-settings-server-internal'; +import type { InternalHttpResourcesPreboot } from '@kbn/core-http-resources-server-internal'; + +/** @internal */ +export interface InternalCorePreboot { + analytics: AnalyticsServicePreboot; + context: InternalContextPreboot; + http: InternalHttpServicePreboot; + elasticsearch: InternalElasticsearchServicePreboot; + uiSettings: InternalUiSettingsServicePreboot; + httpResources: InternalHttpResourcesPreboot; + logging: InternalLoggingServicePreboot; + preboot: InternalPrebootServicePreboot; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_setup.ts b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_setup.ts new file mode 100644 index 0000000000000..5e706cd5f5b0c --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_setup.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 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 { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import type { CapabilitiesSetup } from '@kbn/core-capabilities-server'; +import type { DocLinksServiceSetup } from '@kbn/core-doc-links-server'; +import type { I18nServiceSetup } from '@kbn/core-i18n-server'; +import type { InternalElasticsearchServiceSetup } from '@kbn/core-elasticsearch-server-internal'; +import type { InternalEnvironmentServiceSetup } from '@kbn/core-environment-server-internal'; +import type { InternalExecutionContextSetup } from '@kbn/core-execution-context-server-internal'; +import type { InternalContextSetup } from '@kbn/core-http-context-server-internal'; +import type { InternalDeprecationsServiceSetup } from '@kbn/core-deprecations-server-internal'; +import type { InternalHttpResourcesSetup } from '@kbn/core-http-resources-server-internal'; +import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; +import type { InternalLoggingServiceSetup } from '@kbn/core-logging-server-internal'; +import type { InternalMetricsServiceSetup } from '@kbn/core-metrics-server-internal'; +import type { InternalRenderingServiceSetup } from '@kbn/core-rendering-server-internal'; +import type { InternalSavedObjectsServiceSetup } from '@kbn/core-saved-objects-server-internal'; +import type { InternalStatusServiceSetup } from '@kbn/core-status-server-internal'; +import type { InternalUiSettingsServiceSetup } from '@kbn/core-ui-settings-server-internal'; +import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; + +/** @internal */ +export interface InternalCoreSetup { + analytics: AnalyticsServiceSetup; + capabilities: CapabilitiesSetup; + context: InternalContextSetup; + docLinks: DocLinksServiceSetup; + http: InternalHttpServiceSetup; + elasticsearch: InternalElasticsearchServiceSetup; + executionContext: InternalExecutionContextSetup; + i18n: I18nServiceSetup; + savedObjects: InternalSavedObjectsServiceSetup; + status: InternalStatusServiceSetup; + uiSettings: InternalUiSettingsServiceSetup; + environment: InternalEnvironmentServiceSetup; + rendering: InternalRenderingServiceSetup; + httpResources: InternalHttpResourcesSetup; + logging: InternalLoggingServiceSetup; + metrics: InternalMetricsServiceSetup; + deprecations: InternalDeprecationsServiceSetup; + coreUsageData: InternalCoreUsageDataSetup; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_start.ts b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_start.ts new file mode 100644 index 0000000000000..e4d777d137b70 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/src/internal_core_start.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { AnalyticsServiceStart } from '@kbn/core-analytics-server'; +import type { CapabilitiesStart } from '@kbn/core-capabilities-server'; +import type { InternalDeprecationsServiceStart } from '@kbn/core-deprecations-server-internal'; +import type { DocLinksServiceStart } from '@kbn/core-doc-links-server'; +import type { InternalElasticsearchServiceStart } from '@kbn/core-elasticsearch-server-internal'; +import type { InternalExecutionContextStart } from '@kbn/core-execution-context-server-internal'; +import type { InternalHttpServiceStart } from '@kbn/core-http-server-internal'; +import type { InternalMetricsServiceStart } from '@kbn/core-metrics-server-internal'; +import type { InternalSavedObjectsServiceStart } from '@kbn/core-saved-objects-server-internal'; +import type { InternalUiSettingsServiceStart } from '@kbn/core-ui-settings-server-internal'; +import type { CoreUsageDataStart } from '@kbn/core-usage-data-server'; + +/** + * @internal + */ +export interface InternalCoreStart { + analytics: AnalyticsServiceStart; + capabilities: CapabilitiesStart; + elasticsearch: InternalElasticsearchServiceStart; + docLinks: DocLinksServiceStart; + http: InternalHttpServiceStart; + metrics: InternalMetricsServiceStart; + savedObjects: InternalSavedObjectsServiceStart; + uiSettings: InternalUiSettingsServiceStart; + coreUsageData: CoreUsageDataStart; + executionContext: InternalExecutionContextStart; + deprecations: InternalDeprecationsServiceStart; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-internal/tsconfig.json b/packages/core/lifecycle/core-lifecycle-server-internal/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-server-mocks/BUILD.bazel new file mode 100644 index 0000000000000..95f299b0062cd --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/BUILD.bazel @@ -0,0 +1,143 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-lifecycle-server-mocks" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-server-mocks" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/core/analytics/core-analytics-server-mocks", + "//packages/core/capabilities/core-capabilities-server-mocks", + "//packages/core/doc-links/core-doc-links-server-mocks", + "//packages/core/deprecations/core-deprecations-server-mocks", + "//packages/core/elasticsearch/core-elasticsearch-server-mocks", + "//packages/core/environment/core-environment-server-mocks", + "//packages/core/execution-context/core-execution-context-server-mocks", + "//packages/core/http/core-http-context-server-mocks", + "//packages/core/http/core-http-server-mocks", + "//packages/core/http/core-http-resources-server-mocks", + "//packages/core/i18n/core-i18n-server-mocks", + "//packages/core/lifecycle/core-lifecycle-server", + "//packages/core/metrics/core-metrics-server-mocks", + "//packages/core/preboot/core-preboot-server-mocks", + "//packages/core/rendering/core-rendering-server-mocks", + "//packages/core/saved-objects/core-saved-objects-server-mocks", + "//packages/core/status/core-status-server-mocks", + "//packages/core/ui-settings/core-ui-settings-server-mocks", + "//packages/core/usage-data/core-usage-data-server-mocks", + +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-utility-types-jest:npm_module_types", + "//packages/core/analytics/core-analytics-server-mocks:npm_module_types", + "//packages/core/capabilities/core-capabilities-server-mocks:npm_module_types", + "//packages/core/doc-links/core-doc-links-server-mocks:npm_module_types", + "//packages/core/deprecations/core-deprecations-server-mocks:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server-mocks:npm_module_types", + "//packages/core/environment/core-environment-server-mocks:npm_module_types", + "//packages/core/execution-context/core-execution-context-server-mocks:npm_module_types", + "//packages/core/http/core-http-context-server-mocks:npm_module_types", + "//packages/core/http/core-http-server-mocks:npm_module_types", + "//packages/core/http/core-http-resources-server-mocks:npm_module_types", + "//packages/core/i18n/core-i18n-server-mocks:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-server:npm_module_types", + "//packages/core/metrics/core-metrics-server-mocks:npm_module_types", + "//packages/core/preboot/core-preboot-server-mocks:npm_module_types", + "//packages/core/rendering/core-rendering-server-mocks:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-server-mocks:npm_module_types", + "//packages/core/status/core-status-server-mocks:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-server-mocks:npm_module_types", + "//packages/core/usage-data/core-usage-data-server-mocks:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/README.md b/packages/core/lifecycle/core-lifecycle-server-mocks/README.md new file mode 100644 index 0000000000000..6603c268f3d94 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/README.md @@ -0,0 +1,5 @@ +# @kbn/core-lifecycle-server-mocks + +This package contains the mocks for core's server-side lifecycle contracts: +- `coreLifecycleMock` +- `coreInternalLifecycleMock` diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/index.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/index.ts new file mode 100644 index 0000000000000..e17f4db9de973 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { coreLifecycleMock, coreInternalLifecycleMock } from './src'; diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/jest.config.js b/packages/core/lifecycle/core-lifecycle-server-mocks/jest.config.js new file mode 100644 index 0000000000000..3db7ab516cd56 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-server-mocks'], +}; diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-server-mocks/kibana.jsonc new file mode 100644 index 0000000000000..ea9bbadfd57e9 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-server-mocks", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/package.json b/packages/core/lifecycle/core-lifecycle-server-mocks/package.json new file mode 100644 index 0000000000000..ce6bae6105a29 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-lifecycle-server-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_preboot.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_preboot.mock.ts new file mode 100644 index 0000000000000..43446f824faed --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_preboot.mock.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 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 { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { prebootServiceMock } from '@kbn/core-preboot-server-mocks'; +import type { MockedKeys } from '@kbn/utility-types-jest'; +import type { CorePreboot } from '@kbn/core-lifecycle-server'; + +type CorePrebootMockType = MockedKeys & { + elasticsearch: ReturnType; +}; + +export function createCorePrebootMock() { + const mock: CorePrebootMockType = { + analytics: analyticsServiceMock.createAnalyticsServicePreboot(), + elasticsearch: elasticsearchServiceMock.createPreboot(), + http: httpServiceMock.createPrebootContract() as CorePrebootMockType['http'], + preboot: prebootServiceMock.createPrebootContract(), + }; + + return mock; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts new file mode 100644 index 0000000000000..0c4e25e846cab --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import type { CoreSetup, StartServicesAccessor } from '@kbn/core-lifecycle-server'; +import type { MockedKeys } from '@kbn/utility-types-jest'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; +import { i18nServiceMock } from '@kbn/core-i18n-server-mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; +import { statusServiceMock } from '@kbn/core-status-server-mocks'; +import { loggingServiceMock } from '@kbn/core-logging-server-mocks'; +import { metricsServiceMock } from '@kbn/core-metrics-server-mocks'; +import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; +import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks'; +import { createCoreStartMock } from './core_start.mock'; + +type CoreSetupMockType = MockedKeys & { + elasticsearch: ReturnType; + getStartServices: jest.MockedFunction>; +}; + +export function createCoreSetupMock({ + pluginStartDeps = {}, + pluginStartContract, +}: { + pluginStartDeps?: object; + pluginStartContract?: any; +} = {}) { + const httpMock: jest.Mocked = { + ...httpServiceMock.createSetupContract(), + resources: httpResourcesMock.createRegistrar(), + }; + + const uiSettingsMock = { + register: uiSettingsServiceMock.createSetupContract().register, + }; + + const mock: CoreSetupMockType = { + analytics: analyticsServiceMock.createAnalyticsServiceSetup(), + capabilities: capabilitiesServiceMock.createSetupContract(), + docLinks: docLinksServiceMock.createSetupContract(), + elasticsearch: elasticsearchServiceMock.createSetup(), + http: httpMock, + i18n: i18nServiceMock.createSetupContract(), + savedObjects: savedObjectsServiceMock.createInternalSetupContract(), + status: statusServiceMock.createSetupContract(), + uiSettings: uiSettingsMock, + logging: loggingServiceMock.createSetupContract(), + metrics: metricsServiceMock.createSetupContract(), + deprecations: deprecationsServiceMock.createSetupContract(), + executionContext: executionContextServiceMock.createInternalSetupContract(), + coreUsageData: { + registerUsageCounter: coreUsageDataServiceMock.createSetupContract().registerUsageCounter, + }, + getStartServices: jest + .fn, object, any]>, []>() + .mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]), + }; + + return mock; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_start.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_start.mock.ts new file mode 100644 index 0000000000000..763a9c403eb39 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_start.mock.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import type { CoreStart } from '@kbn/core-lifecycle-server'; +import { metricsServiceMock } from '@kbn/core-metrics-server-mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks'; +import type { MockedKeys } from '@kbn/utility-types-jest'; + +export function createCoreStartMock() { + const mock: MockedKeys = { + analytics: analyticsServiceMock.createAnalyticsServiceStart(), + capabilities: capabilitiesServiceMock.createStartContract(), + docLinks: docLinksServiceMock.createStartContract(), + elasticsearch: elasticsearchServiceMock.createStart(), + http: httpServiceMock.createStartContract(), + metrics: metricsServiceMock.createStartContract(), + savedObjects: savedObjectsServiceMock.createStartContract(), + uiSettings: uiSettingsServiceMock.createStartContract(), + coreUsageData: coreUsageDataServiceMock.createStartContract(), + executionContext: executionContextServiceMock.createInternalStartContract(), + }; + + return mock; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts new file mode 100644 index 0000000000000..66f9c1d818351 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { createCorePrebootMock } from './core_preboot.mock'; +import { createCoreSetupMock } from './core_setup.mock'; +import { createCoreStartMock } from './core_start.mock'; + +import { createInternalCorePrebootMock } from './internal_core_preboot.mock'; +import { createInternalCoreSetupMock } from './internal_core_setup.mock'; +import { createInternalCoreStartMock } from './internal_core_start.mock'; + +export const coreLifecycleMock = { + createPreboot: createCorePrebootMock, + createCoreSetup: createCoreSetupMock, + createCoreStart: createCoreStartMock, +}; + +export const coreInternalLifecycleMock = { + createInternalPreboot: createInternalCorePrebootMock, + createInternalSetup: createInternalCoreSetupMock, + createInternalStart: createInternalCoreStartMock, +}; diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_preboot.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_preboot.mock.ts new file mode 100644 index 0000000000000..08c6d269f1e38 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_preboot.mock.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { contextServiceMock } from '@kbn/core-http-context-server-mocks'; +import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { loggingServiceMock } from '@kbn/core-logging-server-mocks'; +import { prebootServiceMock } from '@kbn/core-preboot-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; + +export function createInternalCorePrebootMock() { + const prebootDeps = { + analytics: analyticsServiceMock.createAnalyticsServicePreboot(), + context: contextServiceMock.createPrebootContract(), + elasticsearch: elasticsearchServiceMock.createInternalPreboot(), + http: httpServiceMock.createInternalPrebootContract(), + httpResources: httpResourcesMock.createPrebootContract(), + uiSettings: uiSettingsServiceMock.createPrebootContract(), + logging: loggingServiceMock.createInternalPrebootContract(), + preboot: prebootServiceMock.createInternalPrebootContract(), + }; + return prebootDeps; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_setup.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_setup.mock.ts new file mode 100644 index 0000000000000..cddb9a49dab3c --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_setup.mock.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks'; +import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { environmentServiceMock } from '@kbn/core-environment-server-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; +import { contextServiceMock } from '@kbn/core-http-context-server-mocks'; +import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { i18nServiceMock } from '@kbn/core-i18n-server-mocks'; +import { loggingServiceMock } from '@kbn/core-logging-server-mocks'; +import { metricsServiceMock } from '@kbn/core-metrics-server-mocks'; +import { renderingServiceMock } from '@kbn/core-rendering-server-mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; +import { statusServiceMock } from '@kbn/core-status-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks'; + +export function createInternalCoreSetupMock() { + const setupDeps = { + analytics: analyticsServiceMock.createAnalyticsServiceSetup(), + capabilities: capabilitiesServiceMock.createSetupContract(), + context: contextServiceMock.createSetupContract(), + docLinks: docLinksServiceMock.createSetupContract(), + elasticsearch: elasticsearchServiceMock.createInternalSetup(), + http: httpServiceMock.createInternalSetupContract(), + savedObjects: savedObjectsServiceMock.createInternalSetupContract(), + status: statusServiceMock.createInternalSetupContract(), + environment: environmentServiceMock.createSetupContract(), + i18n: i18nServiceMock.createSetupContract(), + httpResources: httpResourcesMock.createSetupContract(), + rendering: renderingServiceMock.createSetupContract(), + uiSettings: uiSettingsServiceMock.createSetupContract(), + logging: loggingServiceMock.createInternalSetupContract(), + metrics: metricsServiceMock.createInternalSetupContract(), + deprecations: deprecationsServiceMock.createInternalSetupContract(), + executionContext: executionContextServiceMock.createInternalSetupContract(), + coreUsageData: coreUsageDataServiceMock.createSetupContract(), + }; + return setupDeps; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_start.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_start.mock.ts new file mode 100644 index 0000000000000..6283fa3ce6a88 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/internal_core_start.mock.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks'; +import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; +import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { metricsServiceMock } from '@kbn/core-metrics-server-mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks'; + +export function createInternalCoreStartMock() { + const startDeps = { + analytics: analyticsServiceMock.createAnalyticsServiceStart(), + capabilities: capabilitiesServiceMock.createStartContract(), + docLinks: docLinksServiceMock.createStartContract(), + elasticsearch: elasticsearchServiceMock.createInternalStart(), + http: httpServiceMock.createInternalStartContract(), + metrics: metricsServiceMock.createInternalStartContract(), + savedObjects: savedObjectsServiceMock.createInternalStartContract(), + uiSettings: uiSettingsServiceMock.createStartContract(), + coreUsageData: coreUsageDataServiceMock.createStartContract(), + executionContext: executionContextServiceMock.createInternalStartContract(), + deprecations: deprecationsServiceMock.createInternalStartContract(), + }; + return startDeps; +} diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/tsconfig.json b/packages/core/lifecycle/core-lifecycle-server-mocks/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/lifecycle/core-lifecycle-server/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-server/BUILD.bazel new file mode 100644 index 0000000000000..85b3b6ab1ca97 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/BUILD.bazel @@ -0,0 +1,122 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-lifecycle-server" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-server" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/analytics/core-analytics-server:npm_module_types", + "//packages/core/capabilities/core-capabilities-server:npm_module_types", + "//packages/core/deprecations/core-deprecations-server:npm_module_types", + "//packages/core/doc-links/core-doc-links-server:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server:npm_module_types", + "//packages/core/execution-context/core-execution-context-server:npm_module_types", + "//packages/core/http/core-http-server:npm_module_types", + "//packages/core/http/core-http-request-handler-context-server:npm_module_types", + "//packages/core/http/core-http-resources-server:npm_module_types", + "//packages/core/i18n/core-i18n-server:npm_module_types", + "//packages/core/logging/core-logging-server:npm_module_types", + "//packages/core/metrics/core-metrics-server:npm_module_types", + "//packages/core/preboot/core-preboot-server:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-server:npm_module_types", + "//packages/core/status/core-status-server:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-server:npm_module_types", + "//packages/core/usage-data/core-usage-data-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-server/README.md b/packages/core/lifecycle/core-lifecycle-server/README.md new file mode 100644 index 0000000000000..5d06aa257f81f --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/README.md @@ -0,0 +1,7 @@ +# @kbn/core-lifecycle-server + +This package contains the public types for core's server-side lifecycle contracts and services accessor: +- `CorePreboot` +- `CoreSetup` +- `CoreStart` +- `StartServicesAccessor` diff --git a/packages/core/lifecycle/core-lifecycle-server/index.ts b/packages/core/lifecycle/core-lifecycle-server/index.ts new file mode 100644 index 0000000000000..5e8b379724036 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { CorePreboot, CoreSetup, CoreStart, StartServicesAccessor } from './src'; diff --git a/packages/core/lifecycle/core-lifecycle-server/jest.config.js b/packages/core/lifecycle/core-lifecycle-server/jest.config.js new file mode 100644 index 0000000000000..3d48a32bd7610 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-server'], +}; diff --git a/packages/core/lifecycle/core-lifecycle-server/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-server/kibana.jsonc new file mode 100644 index 0000000000000..867db6cc2dab0 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-server", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-server/package.json b/packages/core/lifecycle/core-lifecycle-server/package.json new file mode 100644 index 0000000000000..da5e093f9c250 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-lifecycle-server", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts b/packages/core/lifecycle/core-lifecycle-server/src/core_preboot.ts new file mode 100644 index 0000000000000..893854149d7d2 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/src/core_preboot.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 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 { AnalyticsServicePreboot } from '@kbn/core-analytics-server'; +import type { HttpServicePreboot } from '@kbn/core-http-server'; +import type { PrebootServicePreboot } from '@kbn/core-preboot-server'; +import type { ElasticsearchServicePreboot } from '@kbn/core-elasticsearch-server'; +import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; + +/** + * Context passed to the `setup` method of `preboot` plugins. + * @public + */ +export interface CorePreboot { + /** {@link AnalyticsServicePreboot} */ + analytics: AnalyticsServicePreboot; + /** {@link ElasticsearchServicePreboot} */ + elasticsearch: ElasticsearchServicePreboot; + /** {@link HttpServicePreboot} */ + http: HttpServicePreboot; + /** {@link PrebootServicePreboot} */ + preboot: PrebootServicePreboot; +} diff --git a/packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts b/packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts new file mode 100644 index 0000000000000..1565e11b13777 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/src/core_setup.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import { CapabilitiesSetup } from '@kbn/core-capabilities-server'; +import { DeprecationsServiceSetup } from '@kbn/core-deprecations-server'; +import { DocLinksServiceSetup } from '@kbn/core-doc-links-server'; +import { ElasticsearchServiceSetup } from '@kbn/core-elasticsearch-server'; +import { ExecutionContextSetup } from '@kbn/core-execution-context-server'; +import { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import { HttpResources } from '@kbn/core-http-resources-server'; +import { HttpServiceSetup } from '@kbn/core-http-server'; +import { I18nServiceSetup } from '@kbn/core-i18n-server'; +import { LoggingServiceSetup } from '@kbn/core-logging-server'; +import { MetricsServiceSetup } from '@kbn/core-metrics-server'; +import { SavedObjectsServiceSetup } from '@kbn/core-saved-objects-server'; +import { StatusServiceSetup } from '@kbn/core-status-server'; +import { UiSettingsServiceSetup } from '@kbn/core-ui-settings-server'; +import { CoreUsageDataSetup } from '@kbn/core-usage-data-server'; +import { CoreStart } from './core_start'; + +/** + * Context passed to the `setup` method of `standard` plugins. + * + * @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same + * as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`. + * @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the + * consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`. + * @public + */ +export interface CoreSetup { + /** {@link AnalyticsServiceSetup} */ + analytics: AnalyticsServiceSetup; + /** {@link CapabilitiesSetup} */ + capabilities: CapabilitiesSetup; + /** {@link DocLinksServiceSetup} */ + docLinks: DocLinksServiceSetup; + /** {@link ElasticsearchServiceSetup} */ + elasticsearch: ElasticsearchServiceSetup; + /** {@link ExecutionContextSetup} */ + executionContext: ExecutionContextSetup; + /** {@link HttpServiceSetup} */ + http: HttpServiceSetup & { + /** {@link HttpResources} */ + resources: HttpResources; + }; + /** {@link I18nServiceSetup} */ + i18n: I18nServiceSetup; + /** {@link LoggingServiceSetup} */ + logging: LoggingServiceSetup; + /** {@link MetricsServiceSetup} */ + metrics: MetricsServiceSetup; + /** {@link SavedObjectsServiceSetup} */ + savedObjects: SavedObjectsServiceSetup; + /** {@link StatusServiceSetup} */ + status: StatusServiceSetup; + /** {@link UiSettingsServiceSetup} */ + uiSettings: UiSettingsServiceSetup; + /** {@link DeprecationsServiceSetup} */ + deprecations: DeprecationsServiceSetup; + /** {@link StartServicesAccessor} */ + getStartServices: StartServicesAccessor; + /** @internal {@link CoreUsageDataSetup} */ + coreUsageData: CoreUsageDataSetup; +} + +/** + * Allows plugins to get access to APIs available in start inside async handlers. + * Promise will not resolve until Core and plugin dependencies have completed `start`. + * This should only be used inside handlers registered during `setup` that will only be executed + * after `start` lifecycle. + * + * @public + */ +export type StartServicesAccessor< + TPluginsStart extends object = object, + TStart = unknown +> = () => Promise<[CoreStart, TPluginsStart, TStart]>; diff --git a/packages/core/lifecycle/core-lifecycle-server/src/core_start.ts b/packages/core/lifecycle/core-lifecycle-server/src/core_start.ts new file mode 100644 index 0000000000000..53c989154af08 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/src/core_start.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 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 { AnalyticsServiceStart } from '@kbn/core-analytics-server'; +import { CapabilitiesStart } from '@kbn/core-capabilities-server'; +import { DocLinksServiceStart } from '@kbn/core-doc-links-server'; +import { ElasticsearchServiceStart } from '@kbn/core-elasticsearch-server'; +import { ExecutionContextStart } from '@kbn/core-execution-context-server'; +import { HttpServiceStart } from '@kbn/core-http-server'; +import { MetricsServiceStart } from '@kbn/core-metrics-server'; +import { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server'; +import { UiSettingsServiceStart } from '@kbn/core-ui-settings-server'; +import { CoreUsageDataStart } from '@kbn/core-usage-data-server'; + +/** + * Context passed to the plugins `start` method. + * + * @public + */ +export interface CoreStart { + /** {@link AnalyticsServiceStart} */ + analytics: AnalyticsServiceStart; + /** {@link CapabilitiesStart} */ + capabilities: CapabilitiesStart; + /** {@link DocLinksServiceStart} */ + docLinks: DocLinksServiceStart; + /** {@link ElasticsearchServiceStart} */ + elasticsearch: ElasticsearchServiceStart; + /** {@link ExecutionContextStart} */ + executionContext: ExecutionContextStart; + /** {@link HttpServiceStart} */ + http: HttpServiceStart; + /** {@link MetricsServiceStart} */ + metrics: MetricsServiceStart; + /** {@link SavedObjectsServiceStart} */ + savedObjects: SavedObjectsServiceStart; + /** {@link UiSettingsServiceStart} */ + uiSettings: UiSettingsServiceStart; + /** @internal {@link CoreUsageDataStart} */ + coreUsageData: CoreUsageDataStart; +} diff --git a/packages/core/lifecycle/core-lifecycle-server/src/index.ts b/packages/core/lifecycle/core-lifecycle-server/src/index.ts new file mode 100644 index 0000000000000..37f4a6c60fd14 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/src/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export type { CorePreboot } from './core_preboot'; +export type { CoreSetup, StartServicesAccessor } from './core_setup'; +export type { CoreStart } from './core_start'; diff --git a/packages/core/lifecycle/core-lifecycle-server/tsconfig.json b/packages/core/lifecycle/core-lifecycle-server/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/logging/core-logging-server-internal/src/appenders/rewrite/policies/meta/meta_policy.test.ts b/packages/core/logging/core-logging-server-internal/src/appenders/rewrite/policies/meta/meta_policy.test.ts index 3c12e479cc834..86d4df2d1d709 100644 --- a/packages/core/logging/core-logging-server-internal/src/appenders/rewrite/policies/meta/meta_policy.test.ts +++ b/packages/core/logging/core-logging-server-internal/src/appenders/rewrite/policies/meta/meta_policy.test.ts @@ -124,7 +124,7 @@ describe('MetaRewritePolicy', () => { "error": Object {}, "tags": Array [ "0", - undefined, + , ], } `); diff --git a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts index 351e2aca43f56..b17cb6c3195ae 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts @@ -30,7 +30,7 @@ describe('MetricsService', () => { let metricsService: MetricsService; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const configService = configServiceMock.create({ atPath: { interval: moment.duration(testInterval) }, diff --git a/packages/core/overlays/core-overlays-browser-internal/src/banners/user_banner_service.test.ts b/packages/core/overlays/core-overlays-browser-internal/src/banners/user_banner_service.test.ts index 378de1611a746..1936211774231 100644 --- a/packages/core/overlays/core-overlays-browser-internal/src/banners/user_banner_service.test.ts +++ b/packages/core/overlays/core-overlays-browser-internal/src/banners/user_banner_service.test.ts @@ -56,7 +56,7 @@ describe('OverlayBannersService', () => { }); it('dismisses banner after timeout', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startService('testing banner!'); expect(banners.remove).not.toHaveBeenCalled(); diff --git a/packages/core/plugins/core-plugins-server-internal/BUILD.bazel b/packages/core/plugins/core-plugins-server-internal/BUILD.bazel new file mode 100644 index 0000000000000..61044f11d5b51 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/BUILD.bazel @@ -0,0 +1,155 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-plugins-server-internal" +PKG_REQUIRE_NAME = "@kbn/core-plugins-server-internal" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//moment", + "@npm//rxjs", + "@npm//semver", + "@npm//type-detect", + "@npm//lodash", + "//packages/kbn-std", + "//packages/kbn-config", + "//packages/kbn-config-schema", + "//packages/kbn-logging", + "//packages/kbn-utils", + "//packages/core/base/core-base-common", + "//packages/core/base/core-base-server-internal", + "//packages/core/lifecycle/core-lifecycle-server-internal", + "//packages/core/elasticsearch/core-elasticsearch-server-internal", + "//packages/core/node/core-node-server", + "//packages/core/saved-objects/core-saved-objects-base-server-internal", + # test dependencies + "@npm//mock-fs", + "//packages/kbn-config-mocks", + "//packages/core/base/core-base-server-mocks", + "//packages/core/lifecycle/core-lifecycle-server-mocks", + "//packages/core/logging/core-logging-server-mocks", + "//packages/core/node/core-node-server-mocks", + "//packages/core/plugins/core-plugins-server", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//moment", + "@npm//rxjs", + "@npm//semver", + "@npm//type-detect", + "@npm//lodash", + "//packages/kbn-std:npm_module_types", + "//packages/kbn-config:npm_module_types", + "//packages/kbn-config-schema:npm_module_types", + "//packages/kbn-logging:npm_module_types", + "//packages/kbn-utils:npm_module_types", + "//packages/core/base/core-base-common:npm_module_types", + "//packages/core/base/core-base-server-internal:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server-internal:npm_module_types", + "//packages/core/node/core-node-server:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-base-server-internal:npm_module_types", + "//packages/core/http/core-http-server:npm_module_types", + "//packages/core/http/core-http-request-handler-context-server:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-server:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-server-internal:npm_module_types", + "//packages/core/plugins/core-plugins-server:npm_module_types", + # test dependencies' mocks + "@npm//mock-fs", + "//packages/kbn-config-mocks:npm_module_types", + "//packages/core/base/core-base-server-mocks:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-server-mocks:npm_module_types", + "//packages/core/logging/core-logging-server-mocks:npm_module_types", + "//packages/core/node/core-node-server-mocks:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-server-internal/README.md b/packages/core/plugins/core-plugins-server-internal/README.md new file mode 100644 index 0000000000000..7ca4a5600877f --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/README.md @@ -0,0 +1,3 @@ +# @kbn/core-plugins-server-internal + +This package contains the internal types and implementation for Core's server-side `plugins` service. diff --git a/packages/core/plugins/core-plugins-server-internal/index.ts b/packages/core/plugins/core-plugins-server-internal/index.ts new file mode 100644 index 0000000000000..072ffda4b4421 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { PluginsService, PluginWrapper, config, isNewPlatformPlugin } from './src'; +export type { + PluginsServiceSetup, + PluginsServiceStart, + DiscoveredPlugins, + PluginDependencies, +} from './src'; diff --git a/packages/core/plugins/core-plugins-server-internal/jest.config.js b/packages/core/plugins/core-plugins-server-internal/jest.config.js new file mode 100644 index 0000000000000..08315583a6f6d --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-server-internal'], +}; diff --git a/packages/core/plugins/core-plugins-server-internal/kibana.jsonc b/packages/core/plugins/core-plugins-server-internal/kibana.jsonc new file mode 100644 index 0000000000000..2354b5ea2054e --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-server-internal", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-server-internal/package.json b/packages/core/plugins/core-plugins-server-internal/package.json new file mode 100644 index 0000000000000..68adae5d08fed --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-plugins-server-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/plugins/create_browser_config.test.ts b/packages/core/plugins/core-plugins-server-internal/src/create_browser_config.test.ts similarity index 98% rename from src/core/server/plugins/create_browser_config.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/create_browser_config.test.ts index ca0366b7477fa..11f55d1bc1edb 100644 --- a/src/core/server/plugins/create_browser_config.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/create_browser_config.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { PluginConfigDescriptor } from './types'; +import type { PluginConfigDescriptor } from '@kbn/core-plugins-server'; import { createBrowserConfig } from './create_browser_config'; import { schema, TypeOf } from '@kbn/config-schema'; diff --git a/src/core/server/plugins/create_browser_config.ts b/packages/core/plugins/core-plugins-server-internal/src/create_browser_config.ts similarity index 98% rename from src/core/server/plugins/create_browser_config.ts rename to packages/core/plugins/core-plugins-server-internal/src/create_browser_config.ts index 0bf812d2e5cce..05844839934b2 100644 --- a/src/core/server/plugins/create_browser_config.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/create_browser_config.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ExposedToBrowserDescriptor, PluginConfigDescriptor } from './types'; +import { ExposedToBrowserDescriptor, PluginConfigDescriptor } from '@kbn/core-plugins-server'; export const createBrowserConfig = ( config: T, diff --git a/src/core/server/plugins/discovery/index.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/index.ts similarity index 100% rename from src/core/server/plugins/discovery/index.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/index.ts diff --git a/src/core/server/plugins/discovery/is_camel_case.test.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/is_camel_case.test.ts similarity index 100% rename from src/core/server/plugins/discovery/is_camel_case.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/is_camel_case.test.ts diff --git a/src/core/server/plugins/discovery/is_camel_case.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/is_camel_case.ts similarity index 100% rename from src/core/server/plugins/discovery/is_camel_case.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/is_camel_case.ts diff --git a/src/core/server/plugins/discovery/plugin_discovery_error.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_discovery_error.ts similarity index 100% rename from src/core/server/plugins/discovery/plugin_discovery_error.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_discovery_error.ts diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.test.mocks.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.test.mocks.ts similarity index 100% rename from src/core/server/plugins/discovery/plugin_manifest_parser.test.mocks.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.test.mocks.ts diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.test.ts similarity index 100% rename from src/core/server/plugins/discovery/plugin_manifest_parser.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.test.ts diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts similarity index 99% rename from src/core/server/plugins/discovery/plugin_manifest_parser.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts index 0a54899856ac1..5402b9218620d 100644 --- a/src/core/server/plugins/discovery/plugin_manifest_parser.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts @@ -13,7 +13,7 @@ import { promisify } from 'util'; import { snakeCase } from 'lodash'; import { isConfigPath, PackageInfo } from '@kbn/config'; import { PluginType } from '@kbn/core-base-common'; -import { PluginManifest } from '../types'; +import { PluginManifest } from '@kbn/core-plugins-server'; import { PluginDiscoveryError } from './plugin_discovery_error'; import { isCamelCase } from './is_camel_case'; diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.test.mocks.ts similarity index 100% rename from src/core/server/plugins/discovery/plugins_discovery.test.mocks.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.test.mocks.ts diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.test.ts similarity index 99% rename from src/core/server/plugins/discovery/plugins_discovery.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.test.ts index 03c86fb46b5eb..8c1c50e8a612c 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.test.ts @@ -22,7 +22,7 @@ import type { NodeInfo } from '@kbn/core-node-server'; import { PluginsConfig, PluginsConfigType, config } from '../plugins_config'; import type { InstanceInfo } from '../plugin_context'; import { discover } from './plugins_discovery'; -import { PluginType } from '../types'; +import { PluginType } from '@kbn/core-base-common'; const KIBANA_ROOT = process.cwd(); diff --git a/src/core/server/plugins/discovery/plugins_discovery.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.ts similarity index 100% rename from src/core/server/plugins/discovery/plugins_discovery.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/plugins_discovery.ts diff --git a/src/core/server/plugins/discovery/scan_plugin_search_paths.test.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/scan_plugin_search_paths.test.ts similarity index 100% rename from src/core/server/plugins/discovery/scan_plugin_search_paths.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/scan_plugin_search_paths.test.ts diff --git a/src/core/server/plugins/discovery/scan_plugin_search_paths.ts b/packages/core/plugins/core-plugins-server-internal/src/discovery/scan_plugin_search_paths.ts similarity index 100% rename from src/core/server/plugins/discovery/scan_plugin_search_paths.ts rename to packages/core/plugins/core-plugins-server-internal/src/discovery/scan_plugin_search_paths.ts diff --git a/src/core/server/plugins/index.ts b/packages/core/plugins/core-plugins-server-internal/src/index.ts similarity index 87% rename from src/core/server/plugins/index.ts rename to packages/core/plugins/core-plugins-server-internal/src/index.ts index 2111d467ef3c2..3eb852b641fcd 100644 --- a/src/core/server/plugins/index.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/index.ts @@ -15,4 +15,5 @@ export type { export { config } from './plugins_config'; /** @internal */ export { isNewPlatformPlugin } from './discovery'; -export * from './types'; +export type { PluginDependencies } from './types'; +export { PluginWrapper } from './plugin'; diff --git a/src/core/server/plugins/legacy_config.test.ts b/packages/core/plugins/core-plugins-server-internal/src/legacy_config.test.ts similarity index 66% rename from src/core/server/plugins/legacy_config.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/legacy_config.test.ts index ca7a2d8a5454e..2bd50db020d0e 100644 --- a/src/core/server/plugins/legacy_config.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/legacy_config.test.ts @@ -5,37 +5,17 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - import { take } from 'rxjs/operators'; -import { ConfigService, Env } from '@kbn/config'; -import { getEnvOptions, rawConfigServiceMock } from '@kbn/config-mocks'; import { getGlobalConfig, getGlobalConfig$ } from './legacy_config'; -import { REPO_ROOT } from '@kbn/utils'; -import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { duration } from 'moment'; import { fromRoot } from '@kbn/utils'; import { ByteSizeValue } from '@kbn/config-schema'; -import { Server } from '../server'; +import { createCoreContextConfigServiceMock } from './test_helpers'; describe('Legacy config', () => { - let env: Env; - let logger: ReturnType; - - beforeEach(() => { - env = Env.createDefault(REPO_ROOT, getEnvOptions()); - logger = loggingSystemMock.create(); - }); - - const createConfigService = (rawConfig: Record = {}): ConfigService => { - const rawConfigService = rawConfigServiceMock.create({ rawConfig }); - const server = new Server(rawConfigService, env, logger); - server.setupCoreConfig(); - return server.configService; - }; - describe('getGlobalConfig', () => { it('should return the global config', async () => { - const configService = createConfigService(); + const configService = createCoreContextConfigServiceMock(); await configService.validate(); const legacyConfig = getGlobalConfig(configService); @@ -54,7 +34,7 @@ describe('Legacy config', () => { describe('getGlobalConfig$', () => { it('should return an observable for the global config', async () => { - const configService = createConfigService(); + const configService = createCoreContextConfigServiceMock(); const legacyConfig = await getGlobalConfig$(configService).pipe(take(1)).toPromise(); diff --git a/src/core/server/plugins/legacy_config.ts b/packages/core/plugins/core-plugins-server-internal/src/legacy_config.ts similarity index 96% rename from src/core/server/plugins/legacy_config.ts rename to packages/core/plugins/core-plugins-server-internal/src/legacy_config.ts index de86345c5b7ba..46e792d6b226d 100644 --- a/src/core/server/plugins/legacy_config.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/legacy_config.ts @@ -20,7 +20,7 @@ import { type SavedObjectsConfigType, savedObjectsConfig, } from '@kbn/core-saved-objects-base-server-internal'; -import { SharedGlobalConfig, SharedGlobalConfigKeys } from './types'; +import { SharedGlobalConfig, SharedGlobalConfigKeys } from '@kbn/core-plugins-server'; const createGlobalConfig = ({ elasticsearch, diff --git a/src/core/server/plugins/plugin.test.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin.test.ts similarity index 98% rename from src/core/server/plugins/plugin.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugin.test.ts index 538c9539b2a68..008b8eaf6665a 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin.test.ts @@ -17,10 +17,11 @@ import type { CoreContext } from '@kbn/core-base-server-internal'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import type { NodeInfo } from '@kbn/core-node-server'; import { nodeServiceMock } from '@kbn/core-node-server-mocks'; -import { coreMock } from '../mocks'; - +import type { PluginManifest } from '@kbn/core-plugins-server'; import { PluginWrapper } from './plugin'; -import { PluginManifest, PluginType } from './types'; +import { PluginType } from '@kbn/core-base-common'; +import { coreInternalLifecycleMock } from '@kbn/core-lifecycle-server-mocks'; + import { createPluginInitializerContext, createPluginSetupContext, @@ -72,7 +73,7 @@ let coreContext: CoreContext; let instanceInfo: InstanceInfo; let nodeInfo: NodeInfo; -const setupDeps = coreMock.createInternalSetup(); +const setupDeps = coreInternalLifecycleMock.createInternalSetup(); beforeEach(() => { coreId = Symbol('core'); diff --git a/src/core/server/plugins/plugin.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin.ts similarity index 97% rename from src/core/server/plugins/plugin.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugin.ts index 9ddab175d313a..5446e983676c0 100644 --- a/src/core/server/plugins/plugin.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin.ts @@ -12,18 +12,17 @@ import { firstValueFrom, Subject } from 'rxjs'; import { isPromise } from '@kbn/std'; import { isConfigSchema } from '@kbn/config-schema'; import type { Logger } from '@kbn/logging'; -import { PluginType } from '@kbn/core-base-common'; -import { +import { type PluginOpaqueId, PluginType } from '@kbn/core-base-common'; +import type { AsyncPlugin, Plugin, PluginConfigDescriptor, PluginInitializer, PluginInitializerContext, PluginManifest, - PluginOpaqueId, PrebootPlugin, -} from './types'; -import { CorePreboot, CoreSetup, CoreStart } from '..'; +} from '@kbn/core-plugins-server'; +import type { CorePreboot, CoreSetup, CoreStart } from '@kbn/core-lifecycle-server'; const OSS_PATH_REGEX = /[\/|\\]src[\/|\\]plugins[\/|\\]/; // Matches src/plugins directory on POSIX and Windows const XPACK_PATH_REGEX = /[\/|\\]x-pack[\/|\\]plugins[\/|\\]/; // Matches x-pack/plugins directory on POSIX and Windows diff --git a/src/core/server/plugins/plugin_context.test.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.test.ts similarity index 90% rename from src/core/server/plugins/plugin_context.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugin_context.test.ts index 803c5ded6a545..978bf62222f07 100644 --- a/src/core/server/plugins/plugin_context.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.test.ts @@ -8,8 +8,7 @@ import { duration } from 'moment'; import { first } from 'rxjs/operators'; -import { REPO_ROOT } from '@kbn/utils'; -import { fromRoot } from '@kbn/utils'; +import { REPO_ROOT, fromRoot } from '@kbn/utils'; import { rawConfigServiceMock, getEnvOptions, configServiceMock } from '@kbn/config-mocks'; import type { CoreContext } from '@kbn/core-base-server-internal'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; @@ -21,12 +20,15 @@ import { InstanceInfo, } from './plugin_context'; -import { PluginManifest, PluginType } from './types'; -import { Server } from '../server'; +import { PluginType } from '@kbn/core-base-common'; +import { PluginManifest } from '@kbn/core-plugins-server'; import { schema, ByteSizeValue } from '@kbn/config-schema'; import { ConfigService, Env } from '@kbn/config'; import { PluginWrapper } from './plugin'; -import { coreMock } from '../mocks'; + +import { coreInternalLifecycleMock } from '@kbn/core-lifecycle-server-mocks'; +import { mockCoreContext } from '@kbn/core-base-server-mocks'; +import { createCoreContextConfigServiceMock } from './test_helpers'; function createPluginManifest(manifestProps: Partial = {}): PluginManifest { return { @@ -54,7 +56,6 @@ describe('createPluginInitializerContext', () => { let opaqueId: symbol; let env: Env; let coreContext: CoreContext; - let server: Server; let instanceInfo: InstanceInfo; let nodeInfo: NodeInfo; @@ -67,10 +68,11 @@ describe('createPluginInitializerContext', () => { }; nodeInfo = nodeServiceMock.createInternalPrebootContract(); env = Env.createDefault(REPO_ROOT, getEnvOptions()); - const config$ = rawConfigServiceMock.create({ rawConfig: {} }); - server = new Server(config$, env, logger); - server.setupCoreConfig(); - coreContext = { coreId, env, logger, configService: server.configService }; + coreContext = mockCoreContext.create({ + env, + logger, + configService: configServiceMock.create(), + }); }); describe('context.config', () => { @@ -115,7 +117,12 @@ describe('createPluginInitializerContext', () => { }); it('config.globalConfig$ should be an observable for the global config', async () => { + const configService = createCoreContextConfigServiceMock(); + + coreContext = { coreId, env, logger, configService }; + const manifest = createPluginManifest(); + const pluginInitializerContext = createPluginInitializerContext({ coreContext, opaqueId, @@ -229,7 +236,7 @@ describe('createPluginPrebootSetupContext', () => { }), }); - const corePreboot = coreMock.createInternalPreboot(); + const corePreboot = coreInternalLifecycleMock.createInternalPreboot(); const prebootSetupContext = createPluginPrebootSetupContext(coreContext, corePreboot, plugin); const holdSetupPromise = Promise.resolve(undefined); diff --git a/src/core/server/plugins/plugin_context.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts similarity index 97% rename from src/core/server/plugins/plugin_context.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts index 97b165617b68e..d1bec41373c9d 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts @@ -11,16 +11,16 @@ import type { CoreContext } from '@kbn/core-base-server-internal'; import type { PluginOpaqueId } from '@kbn/core-base-common'; import type { NodeInfo } from '@kbn/core-node-server'; import type { IRouter, IContextProvider } from '@kbn/core-http-server'; -import type { RequestHandlerContext } from '..'; +import { PluginInitializerContext, PluginManifest } from '@kbn/core-plugins-server'; +import { CorePreboot, CoreSetup, CoreStart } from '@kbn/core-lifecycle-server'; +import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; import { PluginWrapper } from './plugin'; import { PluginsServicePrebootSetupDeps, PluginsServiceSetupDeps, PluginsServiceStartDeps, } from './plugins_service'; -import { PluginInitializerContext, PluginManifest } from './types'; import { getGlobalConfig, getGlobalConfig$ } from './legacy_config'; -import { CorePreboot, CoreSetup, CoreStart } from '..'; /** @internal */ export interface InstanceInfo { diff --git a/src/core/server/plugins/plugins_config.test.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_config.test.ts similarity index 100% rename from src/core/server/plugins/plugins_config.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_config.test.ts diff --git a/src/core/server/plugins/plugins_config.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_config.ts similarity index 100% rename from src/core/server/plugins/plugins_config.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_config.ts diff --git a/src/core/server/plugins/plugins_service.test.mocks.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_service.test.mocks.ts similarity index 100% rename from src/core/server/plugins/plugins_service.test.mocks.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_service.test.mocks.ts diff --git a/src/core/server/plugins/plugins_service.test.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_service.test.ts similarity index 99% rename from src/core/server/plugins/plugins_service.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_service.test.ts index 9e234b871d647..4664db6e710c7 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugins_service.test.ts @@ -19,14 +19,15 @@ import { rawConfigServiceMock, getEnvOptions } from '@kbn/config-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { environmentServiceMock } from '@kbn/core-environment-server-mocks'; import { nodeServiceMock } from '@kbn/core-node-server-mocks'; -import { coreMock } from '../mocks'; +import { coreInternalLifecycleMock } from '@kbn/core-lifecycle-server-mocks'; import { PluginDiscoveryError } from './discovery'; import { PluginWrapper } from './plugin'; import { PluginsService } from './plugins_service'; import { PluginsSystem } from './plugins_system'; import { config } from './plugins_config'; import { take } from 'rxjs/operators'; -import { DiscoveredPlugin, PluginConfigDescriptor, PluginType } from './types'; +import type { PluginConfigDescriptor } from '@kbn/core-plugins-server'; +import { DiscoveredPlugin, PluginType } from '@kbn/core-base-common'; const MockPluginsSystem: jest.Mock> = PluginsSystem as any; @@ -40,9 +41,9 @@ let standardMockPluginSystem: jest.Mocked>; let environmentPreboot: ReturnType; let nodePreboot: ReturnType; -const prebootDeps = coreMock.createInternalPreboot(); -const setupDeps = coreMock.createInternalSetup(); -const startDeps = coreMock.createInternalStart(); +const prebootDeps = coreInternalLifecycleMock.createInternalPreboot(); +const setupDeps = coreInternalLifecycleMock.createInternalSetup(); +const startDeps = coreInternalLifecycleMock.createInternalStart(); const logger = loggingSystemMock.create(); expect.addSnapshotSerializer(createAbsolutePathSerializer()); diff --git a/src/core/server/plugins/plugins_service.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_service.ts similarity index 97% rename from src/core/server/plugins/plugins_service.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_service.ts index 3305ff0a06b43..556cd8331b454 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugins_service.ts @@ -14,17 +14,24 @@ import { getFlattenedObject } from '@kbn/std'; import { Logger } from '@kbn/logging'; import type { IConfigService } from '@kbn/config'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; -import type { PluginName } from '@kbn/core-base-common'; +import { type PluginName, PluginType } from '@kbn/core-base-common'; import type { InternalEnvironmentServicePreboot } from '@kbn/core-environment-server-internal'; import type { InternalNodeServicePreboot } from '@kbn/core-node-server-internal'; import type { InternalPluginInfo, UiPlugins } from '@kbn/core-plugins-base-server-internal'; +import { + InternalCorePreboot, + InternalCoreSetup, + InternalCoreStart, +} from '@kbn/core-lifecycle-server-internal'; +import { PluginConfigDescriptor } from '@kbn/core-plugins-server'; +import type { DiscoveredPlugin } from '@kbn/core-base-common'; import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery'; import { PluginWrapper } from './plugin'; -import { DiscoveredPlugin, PluginConfigDescriptor, PluginDependencies, PluginType } from './types'; + +import type { PluginDependencies } from './types'; import { PluginsConfig, PluginsConfigType } from './plugins_config'; import { PluginsSystem } from './plugins_system'; import { createBrowserConfig } from './create_browser_config'; -import { InternalCorePreboot, InternalCoreSetup, InternalCoreStart } from '../internal_types'; /** @internal */ export type DiscoveredPlugins = { diff --git a/src/core/server/plugins/plugins_system.test.mocks.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_system.test.mocks.ts similarity index 100% rename from src/core/server/plugins/plugins_system.test.mocks.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_system.test.mocks.ts diff --git a/src/core/server/plugins/plugins_system.test.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_system.test.ts similarity index 98% rename from src/core/server/plugins/plugins_system.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_system.test.ts index 0d55db06c091e..4010d548a6219 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugins_system.test.ts @@ -15,7 +15,7 @@ import { import { BehaviorSubject } from 'rxjs'; import { REPO_ROOT } from '@kbn/utils'; -import type { PluginName } from '@kbn/core-base-common'; +import { type PluginName, PluginType } from '@kbn/core-base-common'; import type { CoreContext } from '@kbn/core-base-server-internal'; import { Logger } from '@kbn/logging'; import { Env } from '@kbn/config'; @@ -23,9 +23,8 @@ import { configServiceMock, getEnvOptions } from '@kbn/config-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { PluginWrapper } from './plugin'; -import { PluginType } from './types'; import { PluginsSystem } from './plugins_system'; -import { coreMock } from '../mocks'; +import { coreInternalLifecycleMock } from '@kbn/core-lifecycle-server-mocks'; function createPlugin( id: string, @@ -63,9 +62,9 @@ function createPlugin( }); } -const prebootDeps = coreMock.createInternalPreboot(); -const setupDeps = coreMock.createInternalSetup(); -const startDeps = coreMock.createInternalStart(); +const prebootDeps = coreInternalLifecycleMock.createInternalPreboot(); +const setupDeps = coreInternalLifecycleMock.createInternalSetup(); +const startDeps = coreInternalLifecycleMock.createInternalStart(); let pluginsSystem: PluginsSystem; let configService: ReturnType; @@ -552,7 +551,7 @@ test('`startPlugins` only starts plugins that were setup', async () => { describe('setup', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { jest.useRealTimers(); @@ -589,7 +588,7 @@ describe('setup', () => { describe('start', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { jest.useRealTimers(); @@ -748,7 +747,7 @@ describe('asynchronous plugins', () => { describe('stop', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/core/server/plugins/plugins_system.ts b/packages/core/plugins/core-plugins-server-internal/src/plugins_system.ts similarity index 97% rename from src/core/server/plugins/plugins_system.ts rename to packages/core/plugins/core-plugins-server-internal/src/plugins_system.ts index 57db8e7c70f49..d7c4df71dd4fc 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugins_system.ts @@ -7,17 +7,18 @@ */ import { withTimeout, isPromise } from '@kbn/std'; -import type { PluginName } from '@kbn/core-base-common'; +import type { DiscoveredPlugin, PluginName } from '@kbn/core-base-common'; import type { CoreContext } from '@kbn/core-base-server-internal'; -import { Logger } from '@kbn/logging'; -import { PluginWrapper } from './plugin'; -import { DiscoveredPlugin, PluginDependencies, PluginType } from './types'; +import type { Logger } from '@kbn/logging'; +import { PluginType } from '@kbn/core-base-common'; +import type { PluginWrapper } from './plugin'; +import { type PluginDependencies } from './types'; import { createPluginPrebootSetupContext, createPluginSetupContext, createPluginStartContext, } from './plugin_context'; -import { +import type { PluginsServicePrebootSetupDeps, PluginsServiceSetupDeps, PluginsServiceStartDeps, diff --git a/packages/core/plugins/core-plugins-server-internal/src/test_helpers/create_core_context_config_service.mock.ts b/packages/core/plugins/core-plugins-server-internal/src/test_helpers/create_core_context_config_service.mock.ts new file mode 100644 index 0000000000000..399d45398eefb --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/src/test_helpers/create_core_context_config_service.mock.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 { IConfigService } from '@kbn/config'; +import { configServiceMock } from '@kbn/config-mocks'; +import { ByteSizeValue } from '@kbn/config-schema'; +import { fromRoot } from '@kbn/utils'; +import { duration } from 'moment'; +import { from } from 'rxjs'; + +export const createCoreContextConfigServiceMock = (): IConfigService => { + const configService = configServiceMock.create(); + const getPathConfig = (path: string | string[]) => { + switch (path) { + case 'elasticsearch': + return { + shardTimeout: duration(30, 's'), + requestTimeout: duration(30, 's'), + pingTimeout: duration(30, 's'), + someOtherProps: 'unused', + }; + case 'path': + return { data: fromRoot('data'), someOtherProps: 'unused' }; + case 'savedObjects': + return { maxImportPayloadBytes: new ByteSizeValue(26214400), someOtherProps: 'unused' }; + default: + return {}; + } + }; + configService.atPath.mockImplementation((path) => { + return from([getPathConfig(path)]); + }); + configService.atPathSync.mockImplementation((path) => { + return getPathConfig(path); + }); + + return configService; +}; diff --git a/packages/core/plugins/core-plugins-server-internal/src/test_helpers/index.ts b/packages/core/plugins/core-plugins-server-internal/src/test_helpers/index.ts new file mode 100644 index 0000000000000..86ffb0ec8f407 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/src/test_helpers/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { createCoreContextConfigServiceMock } from './create_core_context_config_service.mock'; diff --git a/src/core/server/plugins/types.test.ts b/packages/core/plugins/core-plugins-server-internal/src/types.test.ts similarity index 96% rename from src/core/server/plugins/types.test.ts rename to packages/core/plugins/core-plugins-server-internal/src/types.test.ts index 4a0e6052a9901..ea1537bf0649e 100644 --- a/src/core/server/plugins/types.test.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/types.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ExposedToBrowserDescriptor } from './types'; +import type { ExposedToBrowserDescriptor } from '@kbn/core-plugins-server'; describe('ExposedToBrowserDescriptor', () => { interface ConfigType { diff --git a/packages/core/plugins/core-plugins-server-internal/src/types.ts b/packages/core/plugins/core-plugins-server-internal/src/types.ts new file mode 100644 index 0000000000000..def1a27a4c26f --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/src/types.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { PluginName, PluginOpaqueId } from '@kbn/core-base-common'; + +/** @internal */ +export interface PluginDependencies { + asNames: ReadonlyMap; + asOpaqueIds: ReadonlyMap; +} diff --git a/packages/core/plugins/core-plugins-server-internal/tsconfig.json b/packages/core/plugins/core-plugins-server-internal/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/plugins/core-plugins-server-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/plugins/core-plugins-server-mocks/BUILD.bazel b/packages/core/plugins/core-plugins-server-mocks/BUILD.bazel new file mode 100644 index 0000000000000..39ca50e2b847c --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/BUILD.bazel @@ -0,0 +1,106 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-plugins-server-mocks" +PKG_REQUIRE_NAME = "@kbn/core-plugins-server-mocks" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/core/plugins/core-plugins-server-internal", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-utility-types:npm_module_types", + "//packages/core/plugins/core-plugins-server-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-server-mocks/README.md b/packages/core/plugins/core-plugins-server-mocks/README.md new file mode 100644 index 0000000000000..2ec4d6313919f --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/README.md @@ -0,0 +1,4 @@ +# @kbn/core-plugins-server-mocks + +This package contains mocks for Core's server-side `plugins` service. +- `pluginsServiceMock` diff --git a/packages/core/plugins/core-plugins-server-mocks/index.ts b/packages/core/plugins/core-plugins-server-mocks/index.ts new file mode 100644 index 0000000000000..ebf3e8864ef33 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { pluginServiceMock } from './src'; diff --git a/packages/core/plugins/core-plugins-server-mocks/jest.config.js b/packages/core/plugins/core-plugins-server-mocks/jest.config.js new file mode 100644 index 0000000000000..f7924be975ac9 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-server-mocks'], +}; diff --git a/packages/core/plugins/core-plugins-server-mocks/kibana.jsonc b/packages/core/plugins/core-plugins-server-mocks/kibana.jsonc new file mode 100644 index 0000000000000..4a1b2c0bd2258 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-server-mocks", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-server-mocks/package.json b/packages/core/plugins/core-plugins-server-mocks/package.json new file mode 100644 index 0000000000000..0af107840be65 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-plugins-server-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/plugins/core-plugins-server-mocks/src/index.ts b/packages/core/plugins/core-plugins-server-mocks/src/index.ts new file mode 100644 index 0000000000000..30b3d50c22b74 --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/src/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { pluginServiceMock } from './plugins_service.mock'; diff --git a/src/core/server/plugins/plugins_service.mock.ts b/packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts similarity index 93% rename from src/core/server/plugins/plugins_service.mock.ts rename to packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts index ee7b35a412e80..58c43a4c30eda 100644 --- a/src/core/server/plugins/plugins_service.mock.ts +++ b/packages/core/plugins/core-plugins-server-mocks/src/plugins_service.mock.ts @@ -7,7 +7,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { PluginsService, PluginsServiceSetup } from './plugins_service'; +import { PluginsService, type PluginsServiceSetup } from '@kbn/core-plugins-server-internal'; type PluginsServiceMock = jest.Mocked>; diff --git a/packages/core/plugins/core-plugins-server-mocks/tsconfig.json b/packages/core/plugins/core-plugins-server-mocks/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/plugins/core-plugins-server-mocks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/plugins/core-plugins-server/BUILD.bazel b/packages/core/plugins/core-plugins-server/BUILD.bazel new file mode 100644 index 0000000000000..ec304498d123c --- /dev/null +++ b/packages/core/plugins/core-plugins-server/BUILD.bazel @@ -0,0 +1,119 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-plugins-server" +PKG_REQUIRE_NAME = "@kbn/core-plugins-server" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//rxjs", + "//packages/kbn-config-schema", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//rxjs", + "//packages/kbn-config:npm_module_types", + "//packages/kbn-config-schema:npm_module_types", + "//packages/kbn-utility-types:npm_module_types", + "//packages/kbn-utils:npm_module_types", + "//packages/kbn-logging:npm_module_types", + "//packages/core/base/core-base-common:npm_module_types", + "//packages/core/node/core-node-server:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server-internal:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-base-server-internal:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-server:npm_module_types", + +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-server/README.md b/packages/core/plugins/core-plugins-server/README.md new file mode 100644 index 0000000000000..1add32cc3e1d4 --- /dev/null +++ b/packages/core/plugins/core-plugins-server/README.md @@ -0,0 +1,3 @@ +# @kbn/core-plugins-server + +This package contains the public types for core's server-side plugins service. diff --git a/packages/core/plugins/core-plugins-server/index.ts b/packages/core/plugins/core-plugins-server/index.ts new file mode 100644 index 0000000000000..47aa0d04ac87c --- /dev/null +++ b/packages/core/plugins/core-plugins-server/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { + PrebootPlugin, + Plugin, + AsyncPlugin, + PluginConfigDescriptor, + PluginConfigSchema, + PluginInitializer, + PluginInitializerContext, + PluginManifest, + SharedGlobalConfig, + MakeUsageFromSchema, + ExposedToBrowserDescriptor, +} from './src'; + +export { SharedGlobalConfigKeys } from './src'; diff --git a/packages/core/plugins/core-plugins-server/jest.config.js b/packages/core/plugins/core-plugins-server/jest.config.js new file mode 100644 index 0000000000000..f03056c0495e2 --- /dev/null +++ b/packages/core/plugins/core-plugins-server/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-server'], +}; diff --git a/packages/core/plugins/core-plugins-server/kibana.jsonc b/packages/core/plugins/core-plugins-server/kibana.jsonc new file mode 100644 index 0000000000000..708281a40646b --- /dev/null +++ b/packages/core/plugins/core-plugins-server/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-server", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-server/package.json b/packages/core/plugins/core-plugins-server/package.json new file mode 100644 index 0000000000000..75fda3c2ef661 --- /dev/null +++ b/packages/core/plugins/core-plugins-server/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-plugins-server", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/plugins/core-plugins-server/src/index.ts b/packages/core/plugins/core-plugins-server/src/index.ts new file mode 100644 index 0000000000000..94ad27dedbf12 --- /dev/null +++ b/packages/core/plugins/core-plugins-server/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { + PrebootPlugin, + Plugin, + AsyncPlugin, + PluginConfigDescriptor, + PluginConfigSchema, + PluginInitializer, + PluginInitializerContext, + PluginManifest, + SharedGlobalConfig, + MakeUsageFromSchema, + ExposedToBrowserDescriptor, +} from './types'; + +export { SharedGlobalConfigKeys } from './shared_global_config'; diff --git a/packages/core/plugins/core-plugins-server/src/shared_global_config.ts b/packages/core/plugins/core-plugins-server/src/shared_global_config.ts new file mode 100644 index 0000000000000..6329b2576ab21 --- /dev/null +++ b/packages/core/plugins/core-plugins-server/src/shared_global_config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const SharedGlobalConfigKeys = { + // We can add more if really needed + elasticsearch: ['shardTimeout', 'requestTimeout', 'pingTimeout'] as const, + path: ['data'] as const, + savedObjects: ['maxImportPayloadBytes'] as const, +}; diff --git a/src/core/server/plugins/types.ts b/packages/core/plugins/core-plugins-server/src/types.ts similarity index 94% rename from src/core/server/plugins/types.ts rename to packages/core/plugins/core-plugins-server/src/types.ts index 699631bc4411e..46773971d35ef 100644 --- a/src/core/server/plugins/types.ts +++ b/packages/core/plugins/core-plugins-server/src/types.ts @@ -8,9 +8,9 @@ import { Observable } from 'rxjs'; import { Type } from '@kbn/config-schema'; -import { RecursiveReadonly } from '@kbn/utility-types'; -import { PathConfigType } from '@kbn/utils'; -import { LoggerFactory } from '@kbn/logging'; +import type { RecursiveReadonly } from '@kbn/utility-types'; +import type { PathConfigType } from '@kbn/utils'; +import type { LoggerFactory } from '@kbn/logging'; import type { ConfigPath, EnvironmentMode, @@ -21,14 +21,10 @@ import type { PluginName, PluginOpaqueId, PluginType } from '@kbn/core-base-comm import type { NodeInfo } from '@kbn/core-node-server'; import type { ElasticsearchConfigType } from '@kbn/core-elasticsearch-server-internal'; import type { SavedObjectsConfigType } from '@kbn/core-saved-objects-base-server-internal'; -import { CorePreboot, CoreSetup, CoreStart } from '..'; - +import type { CorePreboot, CoreSetup, CoreStart } from '@kbn/core-lifecycle-server'; +import { SharedGlobalConfigKeys } from './shared_global_config'; type Maybe = T | undefined; -// re-exporting for now to avoid adapting all imports, will be removed later on in the migration process -export type { PluginName, PluginOpaqueId, DiscoveredPlugin } from '@kbn/core-base-common'; -export { PluginType } from '@kbn/core-base-common'; - /** * Dedicated type for plugin configuration schema. * @@ -131,12 +127,6 @@ export type MakeUsageFromSchema = { : boolean; }; -/** @internal */ -export interface PluginDependencies { - asNames: ReadonlyMap; - asOpaqueIds: ReadonlyMap; -} - /** * Describes the set of required and optional properties plugin can define in its * mandatory JSON manifest file. @@ -303,13 +293,6 @@ export interface AsyncPlugin< stop?(): void; } -export const SharedGlobalConfigKeys = { - // We can add more if really needed - elasticsearch: ['shardTimeout', 'requestTimeout', 'pingTimeout'] as const, - path: ['data'] as const, - savedObjects: ['maxImportPayloadBytes'] as const, -}; - /** * @public */ diff --git a/packages/core/plugins/core-plugins-server/tsconfig.json b/packages/core/plugins/core-plugins-server/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/plugins/core-plugins-server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts index e906f119a6575..83854c3aafdab 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ +import { setImmediate } from 'timers/promises'; import { join } from 'path'; import loadJsonFile from 'load-json-file'; -import { setImmediate } from 'timers/promises'; import { clientProviderInstanceMock, diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/cache.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/cache.test.ts index f4829d33dd714..06a91ce079e60 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/cache.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/cache.test.ts @@ -10,7 +10,7 @@ import { Cache } from './cache'; describe('Cache', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_client.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_client.test.ts index 0467897d2fde6..87a43026b6149 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_client.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_client.test.ts @@ -707,7 +707,7 @@ describe('ui settings', () => { describe('caching', () => { describe('read operations cache user config', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { diff --git a/packages/kbn-ace/BUILD.bazel b/packages/kbn-ace/BUILD.bazel index 91900928a6bca..7f30af32afa95 100644 --- a/packages/kbn-ace/BUILD.bazel +++ b/packages/kbn-ace/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-ace" +PKG_DIRNAME = "kbn-ace" PKG_REQUIRE_NAME = "@kbn/ace" SOURCE_FILES = glob( @@ -97,7 +97,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -106,9 +106,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-alerts/BUILD.bazel b/packages/kbn-alerts/BUILD.bazel index 86a23118abfe0..c9e52274d39f5 100644 --- a/packages/kbn-alerts/BUILD.bazel +++ b/packages/kbn-alerts/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-alerts" +PKG_DIRNAME = "kbn-alerts" PKG_REQUIRE_NAME = "@kbn/alerts" SOURCE_FILES = glob( @@ -89,7 +89,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -98,9 +98,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-analytics/BUILD.bazel b/packages/kbn-analytics/BUILD.bazel index 4c9065c836068..53d0cbf16ddee 100644 --- a/packages/kbn-analytics/BUILD.bazel +++ b/packages/kbn-analytics/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-analytics" +PKG_DIRNAME = "kbn-analytics" PKG_REQUIRE_NAME = "@kbn/analytics" SOURCE_FILES = glob( @@ -92,7 +92,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -101,9 +101,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-apm-config-loader/BUILD.bazel b/packages/kbn-apm-config-loader/BUILD.bazel index 8d83162d204bc..526193788cd92 100644 --- a/packages/kbn-apm-config-loader/BUILD.bazel +++ b/packages/kbn-apm-config-loader/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-apm-config-loader" +PKG_DIRNAME = "kbn-apm-config-loader" PKG_REQUIRE_NAME = "@kbn/apm-config-loader" SOURCE_FILES = glob( @@ -82,7 +82,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -91,9 +91,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-apm-config-loader/index.ts b/packages/kbn-apm-config-loader/index.ts index e2027b2e12c7c..24f46c01b4b3f 100644 --- a/packages/kbn-apm-config-loader/index.ts +++ b/packages/kbn-apm-config-loader/index.ts @@ -10,3 +10,4 @@ export { getConfiguration } from './src/config_loader'; export { initApm } from './src/init_apm'; export { shouldInstrumentClient } from './src/rum_agent_configuration'; export type { ApmConfiguration } from './src/config'; +export { apmConfigSchema } from './src/apm_config'; diff --git a/packages/kbn-apm-config-loader/src/apm_config.ts b/packages/kbn-apm-config-loader/src/apm_config.ts new file mode 100644 index 0000000000000..0e7b1b9546288 --- /dev/null +++ b/packages/kbn-apm-config-loader/src/apm_config.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; + +export const apmConfigSchema = schema.object({ + apm: schema.object( + { + active: schema.maybe(schema.boolean()), + serverUrl: schema.maybe(schema.uri()), + secretToken: schema.maybe(schema.string()), + globalLabels: schema.object({}, { unknowns: 'allow' }), + }, + { unknowns: 'allow' } + ), +}); diff --git a/packages/kbn-apm-synthtrace/BUILD.bazel b/packages/kbn-apm-synthtrace/BUILD.bazel index 2f87b86044915..4107a948e27c8 100644 --- a/packages/kbn-apm-synthtrace/BUILD.bazel +++ b/packages/kbn-apm-synthtrace/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-apm-synthtrace" +PKG_DIRNAME = "kbn-apm-synthtrace" PKG_REQUIRE_NAME = "@kbn/apm-synthtrace" SOURCE_FILES = glob( @@ -61,6 +61,7 @@ TYPES_DEPS = [ "@npm//p-limit", "@npm//@types/node-fetch", "@npm//@types/semver", + "@npm//@types/yargs", ] jsts_transpiler( @@ -92,7 +93,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -101,9 +102,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/serverless.ts b/packages/kbn-apm-synthtrace/src/lib/apm/serverless.ts index b67586c18a074..f2eb47685bf39 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/serverless.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/serverless.ts @@ -33,7 +33,6 @@ export class Serverless extends BaseSpan { ...fields, 'metricset.name': 'app', 'faas.execution': faasExection, - 'faas.id': fields['service.name'], }); } diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts b/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts index e10bb23b1f933..c8287066cc273 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts @@ -7,7 +7,6 @@ */ import { Entity } from '../entity'; -import { generateShortId } from '../utils/generate_id'; import { ApmFields } from './apm_fields'; import { ServerlessInstance } from './serverless_instance'; @@ -33,7 +32,7 @@ export function serverlessFunction({ agentName: string; serviceName?: string; }) { - const faasId = `arn:aws:lambda:us-west-2:${generateShortId()}:function:${functionName}`; + const faasId = `arn:aws:lambda:us-west-2:001:function:${functionName}`; return new ServerlessFunction({ 'service.name': serviceName || faasId, 'faas.id': faasId, diff --git a/packages/kbn-apm-utils/BUILD.bazel b/packages/kbn-apm-utils/BUILD.bazel index ab3004dc47d36..41b28d8c11cfc 100644 --- a/packages/kbn-apm-utils/BUILD.bazel +++ b/packages/kbn-apm-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-apm-utils" +PKG_DIRNAME = "kbn-apm-utils" PKG_REQUIRE_NAME = "@kbn/apm-utils" SOURCE_FILES = glob( @@ -72,7 +72,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -81,9 +81,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-babel-plugin-synthetic-packages/BUILD.bazel b/packages/kbn-babel-plugin-synthetic-packages/BUILD.bazel index da588dab2ce42..a1e6891f23ec5 100644 --- a/packages/kbn-babel-plugin-synthetic-packages/BUILD.bazel +++ b/packages/kbn-babel-plugin-synthetic-packages/BUILD.bazel @@ -44,9 +44,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_DIRNAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-babel-preset/BUILD.bazel b/packages/kbn-babel-preset/BUILD.bazel index 54dc3bafd8ac8..7b4090ceac48e 100644 --- a/packages/kbn-babel-preset/BUILD.bazel +++ b/packages/kbn-babel-preset/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-babel-preset" +PKG_DIRNAME = "kbn-babel-preset" PKG_REQUIRE_NAME = "@kbn/babel-preset" SOURCE_FILES = glob([ @@ -43,7 +43,7 @@ RUNTIME_DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -54,9 +54,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-cli-dev-mode/BUILD.bazel b/packages/kbn-cli-dev-mode/BUILD.bazel index 9b03aaa956b54..90d11fdeb62bb 100644 --- a/packages/kbn-cli-dev-mode/BUILD.bazel +++ b/packages/kbn-cli-dev-mode/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-cli-dev-mode" +PKG_DIRNAME = "kbn-cli-dev-mode" PKG_REQUIRE_NAME = "@kbn/cli-dev-mode" SOURCE_FILES = glob( @@ -110,7 +110,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -119,9 +119,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-coloring/src/shared_components/coloring/palette_configuration.test.tsx b/packages/kbn-coloring/src/shared_components/coloring/palette_configuration.test.tsx index 696baceffb540..f7f8367d9ed7b 100644 --- a/packages/kbn-coloring/src/shared_components/coloring/palette_configuration.test.tsx +++ b/packages/kbn-coloring/src/shared_components/coloring/palette_configuration.test.tsx @@ -61,7 +61,7 @@ describe('palette panel', () => { dataBounds: { min: 0, max: 100 }, }; - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); function changePaletteIn(instance: ReactWrapper, newPaletteName: string) { diff --git a/packages/kbn-config-schema/BUILD.bazel b/packages/kbn-config-schema/BUILD.bazel index aebd34efa2f08..c14ba00345437 100644 --- a/packages/kbn-config-schema/BUILD.bazel +++ b/packages/kbn-config-schema/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-config-schema" +PKG_DIRNAME = "kbn-config-schema" PKG_REQUIRE_NAME = "@kbn/config-schema" SOURCE_FILES = glob( @@ -82,7 +82,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -91,9 +91,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-config/BUILD.bazel b/packages/kbn-config/BUILD.bazel index eef3d336b57dd..4e1066bd7a19b 100644 --- a/packages/kbn-config/BUILD.bazel +++ b/packages/kbn-config/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-config" +PKG_DIRNAME = "kbn-config" PKG_REQUIRE_NAME = "@kbn/config" SOURCE_FILES = glob( @@ -101,7 +101,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -110,9 +110,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-crypto/BUILD.bazel b/packages/kbn-crypto/BUILD.bazel index 4dade7bba6ca2..55ed47a64303a 100644 --- a/packages/kbn-crypto/BUILD.bazel +++ b/packages/kbn-crypto/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-crypto" +PKG_DIRNAME = "kbn-crypto" PKG_REQUIRE_NAME = "@kbn/crypto" SOURCE_FILES = glob( @@ -79,7 +79,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -88,9 +88,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-datemath/BUILD.bazel b/packages/kbn-datemath/BUILD.bazel index ae4e19b9b7c8c..95e93f70e92e1 100644 --- a/packages/kbn-datemath/BUILD.bazel +++ b/packages/kbn-datemath/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "ts_project", "pkg_npm", "pkg_npm_types") -PKG_BASE_NAME = "kbn-datemath" +PKG_DIRNAME = "kbn-datemath" PKG_REQUIRE_NAME = "@kbn/datemath" SOURCE_FILES = glob( @@ -71,7 +71,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -80,9 +80,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-dev-cli-runner/src/run_with_commands.test.ts b/packages/kbn-dev-cli-runner/src/run_with_commands.test.ts index 329e858b08f5e..150765f1d9b6a 100644 --- a/packages/kbn-dev-cli-runner/src/run_with_commands.test.ts +++ b/packages/kbn-dev-cli-runner/src/run_with_commands.test.ts @@ -8,6 +8,7 @@ import { ToolingLog, ToolingLogCollectingWriter } from '@kbn/tooling-log'; import { ProcRunner } from '@kbn/dev-proc-runner'; +jest.mock('./metrics'); import { FlagsReader } from './flags_reader'; import { RunWithCommands } from './run_with_commands'; @@ -48,7 +49,7 @@ it('extends the context using extendContext()', async () => { flagsReader: expect.any(FlagsReader), addCleanupTask: expect.any(Function), procRunner: expect.any(ProcRunner), - statsMeta: expect.any(Map), + statsMeta: undefined, extraContext: true, }); diff --git a/packages/kbn-dev-utils/BUILD.bazel b/packages/kbn-dev-utils/BUILD.bazel index 42543650a1051..849ea8404f32c 100644 --- a/packages/kbn-dev-utils/BUILD.bazel +++ b/packages/kbn-dev-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-dev-utils" +PKG_DIRNAME = "kbn-dev-utils" PKG_REQUIRE_NAME = "@kbn/dev-utils" SOURCE_FILES = glob( @@ -153,7 +153,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -162,9 +162,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-dev-utils/src/diff_strings.ts b/packages/kbn-dev-utils/src/diff_strings.ts index 11b7e574c7560..03ca506fd4c90 100644 --- a/packages/kbn-dev-utils/src/diff_strings.ts +++ b/packages/kbn-dev-utils/src/diff_strings.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import jestDiff from 'jest-diff'; +import { diff as jestDiff } from 'jest-diff'; import stripAnsi from 'strip-ansi'; import Chalk from 'chalk'; diff --git a/packages/kbn-doc-links/BUILD.bazel b/packages/kbn-doc-links/BUILD.bazel index c4849085c0ae2..292560832da85 100644 --- a/packages/kbn-doc-links/BUILD.bazel +++ b/packages/kbn-doc-links/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-doc-links" +PKG_DIRNAME = "kbn-doc-links" PKG_REQUIRE_NAME = "@kbn/doc-links" SOURCE_FILES = glob( @@ -82,7 +82,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -91,9 +91,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 8783f21a1af9f..796e46ecbf6e5 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -50,6 +50,10 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { overview: `${APM_DOCS}guide/${DOC_LINK_VERSION}/apm-overview.html`, tailSamplingPolicies: `${APM_DOCS}guide/${DOC_LINK_VERSION}/configure-tail-based-sampling.html`, elasticAgent: `${APM_DOCS}guide/${DOC_LINK_VERSION}/upgrade-to-apm-integration.html`, + storageExplorer: `${KIBANA_DOCS}storage-explorer.html`, + spanCompression: `${APM_DOCS}guide/${DOC_LINK_VERSION}/span-compression.html`, + transactionSampling: `${APM_DOCS}guide/${DOC_LINK_VERSION}/sampling.html`, + indexLifecycleManagement: `${APM_DOCS}guide/${DOC_LINK_VERSION}/ilm-how-to.html`, }, canvas: { guide: `${KIBANA_DOCS}canvas.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 443de50276691..7affe129b8173 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -35,6 +35,10 @@ export interface DocLinks { readonly overview: string; readonly tailSamplingPolicies: string; readonly elasticAgent: string; + readonly storageExplorer: string; + readonly spanCompression: string; + readonly transactionSampling: string; + readonly indexLifecycleManagement: string; }; readonly canvas: { readonly guide: string; diff --git a/packages/kbn-docs-utils/BUILD.bazel b/packages/kbn-docs-utils/BUILD.bazel index 33687685100e1..5564b87e15f13 100644 --- a/packages/kbn-docs-utils/BUILD.bazel +++ b/packages/kbn-docs-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-docs-utils" +PKG_DIRNAME = "kbn-docs-utils" PKG_REQUIRE_NAME = "@kbn/docs-utils" SOURCE_FILES = glob( @@ -86,7 +86,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -95,9 +95,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-ebt-tools/BUILD.bazel b/packages/kbn-ebt-tools/BUILD.bazel index ca3591e936703..5b318045b9301 100644 --- a/packages/kbn-ebt-tools/BUILD.bazel +++ b/packages/kbn-ebt-tools/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-ebt-tools" +PKG_DIRNAME = "kbn-ebt-tools" PKG_REQUIRE_NAME = "@kbn/ebt-tools" SOURCE_FILES = glob( @@ -72,7 +72,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, @@ -81,9 +81,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-es-archiver/BUILD.bazel b/packages/kbn-es-archiver/BUILD.bazel index 7b0f9f0346630..7d214d913aeae 100644 --- a/packages/kbn-es-archiver/BUILD.bazel +++ b/packages/kbn-es-archiver/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-es-archiver" +PKG_DIRNAME = "kbn-es-archiver" PKG_REQUIRE_NAME = "@kbn/es-archiver" SOURCE_FILES = glob( @@ -94,7 +94,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -103,9 +103,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-es-query/BUILD.bazel b/packages/kbn-es-query/BUILD.bazel index 2a7c445c32aac..a34b58155359d 100644 --- a/packages/kbn-es-query/BUILD.bazel +++ b/packages/kbn-es-query/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//peggy:index.bzl", "peggy") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-es-query" +PKG_DIRNAME = "kbn-es-query" PKG_REQUIRE_NAME = "@kbn/es-query" SOURCE_FILES = glob( @@ -109,7 +109,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [":grammar"], deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -118,9 +118,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-es/BUILD.bazel b/packages/kbn-es/BUILD.bazel index 23ddda10f36e5..2aeaee4071d53 100644 --- a/packages/kbn-es/BUILD.bazel +++ b/packages/kbn-es/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm") -PKG_BASE_NAME = "kbn-es" +PKG_DIRNAME = "kbn-es" PKG_REQUIRE_NAME = "@kbn/es" SOURCE_FILES = glob( @@ -57,7 +57,7 @@ jsts_transpiler( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -66,9 +66,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-eslint-config/BUILD.bazel b/packages/kbn-eslint-config/BUILD.bazel index 73f834f7d5f63..708136256498d 100644 --- a/packages/kbn-eslint-config/BUILD.bazel +++ b/packages/kbn-eslint-config/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-eslint-config" +PKG_DIRNAME = "kbn-eslint-config" PKG_REQUIRE_NAME = "@kbn/eslint-config" SOURCE_FILES = glob([ @@ -34,7 +34,7 @@ RUNTIME_DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -45,9 +45,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-eslint-plugin-eslint/BUILD.bazel b/packages/kbn-eslint-plugin-eslint/BUILD.bazel index c043c4e468db9..0bb2ff549c9f9 100644 --- a/packages/kbn-eslint-plugin-eslint/BUILD.bazel +++ b/packages/kbn-eslint-plugin-eslint/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-eslint-plugin-eslint" +PKG_DIRNAME = "kbn-eslint-plugin-eslint" PKG_REQUIRE_NAME = "@kbn/eslint-plugin-eslint" SOURCE_FILES = glob( @@ -46,7 +46,7 @@ RUNTIME_DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -57,9 +57,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-expect/BUILD.bazel b/packages/kbn-expect/BUILD.bazel index 415b402a3d05c..70ed34ad091ce 100644 --- a/packages/kbn-expect/BUILD.bazel +++ b/packages/kbn-expect/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-expect" +PKG_DIRNAME = "kbn-expect" PKG_REQUIRE_NAME = "@kbn/expect" SOURCE_FILES = glob([ @@ -22,7 +22,7 @@ NPM_MODULE_EXTRA_FILES = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -32,9 +32,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-field-types/BUILD.bazel b/packages/kbn-field-types/BUILD.bazel index 1d5ca19241bba..fa6bf48c39c88 100644 --- a/packages/kbn-field-types/BUILD.bazel +++ b/packages/kbn-field-types/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library",) load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-field-types" +PKG_DIRNAME = "kbn-field-types" PKG_REQUIRE_NAME = "@kbn/field-types" SOURCE_FILES = glob( @@ -87,7 +87,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -96,9 +96,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-flot-charts/BUILD.bazel b/packages/kbn-flot-charts/BUILD.bazel index d819fa05c7d16..ec2655bc2bbf1 100644 --- a/packages/kbn-flot-charts/BUILD.bazel +++ b/packages/kbn-flot-charts/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-flot-charts" +PKG_DIRNAME = "kbn-flot-charts" PKG_REQUIRE_NAME = "@kbn/flot-charts" SOURCE_FILES = glob([ @@ -26,7 +26,7 @@ RUNTIME_DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -37,9 +37,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-generate/BUILD.bazel b/packages/kbn-generate/BUILD.bazel index 098291d8a0877..e4afaec6069b9 100644 --- a/packages/kbn-generate/BUILD.bazel +++ b/packages/kbn-generate/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-generate" +PKG_DIRNAME = "kbn-generate" PKG_REQUIRE_NAME = "@kbn/generate" SOURCE_FILES = glob( @@ -85,7 +85,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -94,9 +94,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap index 9b18465e91be9..cbb21df42a054 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap @@ -44,6 +44,19 @@ exports[`guide card footer snapshots should render the footer when the guide is
diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx index ef9373996297c..cc16977d966a7 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx +++ b/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx @@ -84,18 +84,13 @@ export const UseCaseCard = ({ ); - const descriptionElement = ( - -

{description}

-
- ); + return ( } title={titleElement} - description={descriptionElement} + description={description} footer={footer} betaBadgeProps={{ label: constants[useCase].betaBadgeLabel, diff --git a/packages/kbn-handlebars/BUILD.bazel b/packages/kbn-handlebars/BUILD.bazel index 4e3d283a0be8e..984366123bafb 100644 --- a/packages/kbn-handlebars/BUILD.bazel +++ b/packages/kbn-handlebars/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-handlebars" +PKG_DIRNAME = "kbn-handlebars" PKG_REQUIRE_NAME = "@kbn/handlebars" TYPES_PKG_REQUIRE_NAME = "@types/kbn__handlebars" @@ -84,7 +84,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -93,9 +93,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-i18n-react/BUILD.bazel b/packages/kbn-i18n-react/BUILD.bazel index efba43ef1cf34..cfcf823bec4a8 100644 --- a/packages/kbn-i18n-react/BUILD.bazel +++ b/packages/kbn-i18n-react/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-i18n-react" +PKG_DIRNAME = "kbn-i18n-react" PKG_REQUIRE_NAME = "@kbn/i18n-react" SOURCE_FILES = glob( @@ -89,7 +89,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -98,9 +98,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-i18n/BUILD.bazel b/packages/kbn-i18n/BUILD.bazel index 90079be18cab2..d58fdfc60df1e 100644 --- a/packages/kbn-i18n/BUILD.bazel +++ b/packages/kbn-i18n/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-i18n" +PKG_DIRNAME = "kbn-i18n" PKG_REQUIRE_NAME = "@kbn/i18n" SOURCE_FILES = glob( @@ -89,7 +89,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -98,9 +98,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-interpreter/BUILD.bazel b/packages/kbn-interpreter/BUILD.bazel index d711715d519c8..e2cd2103ddde9 100644 --- a/packages/kbn-interpreter/BUILD.bazel +++ b/packages/kbn-interpreter/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//peggy:index.bzl", "peggy") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-interpreter" +PKG_DIRNAME = "kbn-interpreter" PKG_REQUIRE_NAME = "@kbn/interpreter" SOURCE_FILES = glob( @@ -101,7 +101,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [":grammar"], deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -110,9 +110,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-io-ts-utils/BUILD.bazel b/packages/kbn-io-ts-utils/BUILD.bazel index 48641035223e5..322c44f18a5b8 100644 --- a/packages/kbn-io-ts-utils/BUILD.bazel +++ b/packages/kbn-io-ts-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-io-ts-utils" +PKG_DIRNAME = "kbn-io-ts-utils" PKG_REQUIRE_NAME = "@kbn/io-ts-utils" SOURCE_FILES = glob( @@ -88,7 +88,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -97,9 +97,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-language-documentation-popover/BUILD.bazel b/packages/kbn-language-documentation-popover/BUILD.bazel index d596368bd91ee..2e2eaa3760abb 100644 --- a/packages/kbn-language-documentation-popover/BUILD.bazel +++ b/packages/kbn-language-documentation-popover/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-language-documentation-popover" +PKG_DIRNAME = "kbn-language-documentation-popover" PKG_REQUIRE_NAME = "@kbn/language-documentation-popover" SOURCE_FILES = glob( @@ -101,7 +101,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_webpack"], package_name = PKG_REQUIRE_NAME, @@ -110,9 +110,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-logging-mocks/BUILD.bazel b/packages/kbn-logging-mocks/BUILD.bazel index 1af99a6a62954..78d175af69dec 100644 --- a/packages/kbn-logging-mocks/BUILD.bazel +++ b/packages/kbn-logging-mocks/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-logging-mocks" +PKG_DIRNAME = "kbn-logging-mocks" PKG_REQUIRE_NAME = "@kbn/logging-mocks" SOURCE_FILES = glob( @@ -72,7 +72,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -81,9 +81,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-logging/BUILD.bazel b/packages/kbn-logging/BUILD.bazel index 4d7668cc09650..cf64d4247f328 100644 --- a/packages/kbn-logging/BUILD.bazel +++ b/packages/kbn-logging/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-logging" +PKG_DIRNAME = "kbn-logging" PKG_REQUIRE_NAME = "@kbn/logging" SOURCE_FILES = glob( @@ -74,7 +74,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -83,9 +83,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-mapbox-gl/BUILD.bazel b/packages/kbn-mapbox-gl/BUILD.bazel index a55f5f77897d7..e81aa132d1111 100644 --- a/packages/kbn-mapbox-gl/BUILD.bazel +++ b/packages/kbn-mapbox-gl/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-mapbox-gl" +PKG_DIRNAME = "kbn-mapbox-gl" PKG_REQUIRE_NAME = "@kbn/mapbox-gl" SOURCE_FILES = glob( @@ -84,7 +84,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -93,9 +93,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-monaco/BUILD.bazel b/packages/kbn-monaco/BUILD.bazel index 2ed705e1c81c3..dbf1b3f0af065 100644 --- a/packages/kbn-monaco/BUILD.bazel +++ b/packages/kbn-monaco/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-monaco" +PKG_DIRNAME = "kbn-monaco" PKG_REQUIRE_NAME = "@kbn/monaco" SOURCE_FILES = glob( @@ -113,7 +113,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web", ":target_workers"], package_name = PKG_REQUIRE_NAME, @@ -122,9 +122,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts b/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts index 5d00ad726d031..7af335ed46987 100644 --- a/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts +++ b/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts @@ -24,9 +24,8 @@ const getMockWorker = async () => { } as any; }; -function flushPromises() { - return new Promise((resolve) => setImmediate(resolve)); -} +const flushPromises = () => + new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); describe('Painless DiagnosticAdapter', () => { let diagnosticAdapter: DiagnosticsAdapter; @@ -35,7 +34,7 @@ describe('Painless DiagnosticAdapter', () => { let validation: LangValidation; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/packages/kbn-optimizer/BUILD.bazel b/packages/kbn-optimizer/BUILD.bazel index 0701fa141dd9a..530058c9f5d7e 100644 --- a/packages/kbn-optimizer/BUILD.bazel +++ b/packages/kbn-optimizer/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-optimizer" +PKG_DIRNAME = "kbn-optimizer" PKG_REQUIRE_NAME = "@kbn/optimizer" SOURCE_FILES = glob( @@ -133,7 +133,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -142,9 +142,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts index 694a606883957..c280890f2dff3 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts @@ -11,7 +11,7 @@ import { fakeSchedulers } from 'rxjs-marbles/jest'; import { pipeClosure, debounceTimeBuffer, maybeMap, maybe } from './rxjs_helpers'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); describe('pipeClosure()', () => { it('calls closure on each subscription to setup unique state', async () => { @@ -70,7 +70,7 @@ describe('maybeMap()', () => { describe('debounceTimeBuffer()', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { diff --git a/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts index 91a2f7324806a..08f6cdc61bce3 100644 --- a/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts @@ -58,7 +58,7 @@ const bundleCacheEvent$ = Rx.from(BUNDLES).pipe( ); beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(async () => { diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_cache_key.test.ts b/packages/kbn-optimizer/src/optimizer/optimizer_cache_key.test.ts index 1cfc1b184d87a..d22ba95282002 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_cache_key.test.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_cache_key.test.ts @@ -23,7 +23,7 @@ jest.mock('@kbn/synthetic-package-map', () => { jest.mock('../common/hashes', () => { return { Hashes: class MockHashes { - static ofFiles = jest.fn(() => { + static ofFiles: any = jest.fn(() => { return new MockHashes(); }); diff --git a/packages/kbn-plugin-generator/BUILD.bazel b/packages/kbn-plugin-generator/BUILD.bazel index 587cd546d50fb..d3ad237231c25 100644 --- a/packages/kbn-plugin-generator/BUILD.bazel +++ b/packages/kbn-plugin-generator/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-plugin-generator" +PKG_DIRNAME = "kbn-plugin-generator" PKG_REQUIRE_NAME = "@kbn/plugin-generator" SOURCE_FILES = glob( @@ -102,7 +102,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -111,9 +111,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-plugin-helpers/BUILD.bazel b/packages/kbn-plugin-helpers/BUILD.bazel index 32f8f0a3720db..c1793269c2fee 100644 --- a/packages/kbn-plugin-helpers/BUILD.bazel +++ b/packages/kbn-plugin-helpers/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-plugin-helpers" +PKG_DIRNAME = "kbn-plugin-helpers" PKG_REQUIRE_NAME = "@kbn/plugin-helpers" SOURCE_FILES = glob( @@ -95,7 +95,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -104,9 +104,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-react-field/BUILD.bazel b/packages/kbn-react-field/BUILD.bazel index ccc12245d323f..0a851c9a156cf 100644 --- a/packages/kbn-react-field/BUILD.bazel +++ b/packages/kbn-react-field/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-react-field" +PKG_DIRNAME = "kbn-react-field" PKG_REQUIRE_NAME = "@kbn/react-field" SOURCE_FILES = glob( @@ -51,8 +51,8 @@ TYPES_DEPS = [ "@npm//@elastic/eui", "@npm//@types/classnames", "@npm//@types/jest", - "@npm//@types/prop-types", "@npm//@types/node", + "@npm//@types/prop-types", "@npm//@types/react", ] @@ -99,7 +99,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_webpack"], package_name = PKG_REQUIRE_NAME, @@ -108,9 +108,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-rule-data-utils/BUILD.bazel b/packages/kbn-rule-data-utils/BUILD.bazel index 61146f0b5de31..788ef54533536 100644 --- a/packages/kbn-rule-data-utils/BUILD.bazel +++ b/packages/kbn-rule-data-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-rule-data-utils" +PKG_DIRNAME = "kbn-rule-data-utils" PKG_REQUIRE_NAME = "@kbn/rule-data-utils" SOURCE_FILES = glob( @@ -86,7 +86,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -95,9 +95,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-safer-lodash-set/BUILD.bazel b/packages/kbn-safer-lodash-set/BUILD.bazel index 893719c822859..3a5d07ab38904 100644 --- a/packages/kbn-safer-lodash-set/BUILD.bazel +++ b/packages/kbn-safer-lodash-set/BUILD.bazel @@ -1,6 +1,6 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") -PKG_BASE_NAME = "kbn-safer-lodash-set" +PKG_DIRNAME = "kbn-safer-lodash-set" PKG_REQUIRE_NAME = "@kbn/safer-lodash-set" SOURCE_FILES = glob( @@ -40,7 +40,7 @@ DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -51,9 +51,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( @@ -66,7 +64,7 @@ filegroup( alias( name = "npm_module_types", - actual = PKG_BASE_NAME, + actual = PKG_DIRNAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-securitysolution-autocomplete/BUILD.bazel b/packages/kbn-securitysolution-autocomplete/BUILD.bazel index d09b4cf04c70a..ae396cfb7a18d 100644 --- a/packages/kbn-securitysolution-autocomplete/BUILD.bazel +++ b/packages/kbn-securitysolution-autocomplete/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-autocomplete" +PKG_DIRNAME = "kbn-securitysolution-autocomplete" PKG_REQUIRE_NAME = "@kbn/securitysolution-autocomplete" SOURCE_FILES = glob( @@ -109,7 +109,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -118,9 +118,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-es-utils/BUILD.bazel b/packages/kbn-securitysolution-es-utils/BUILD.bazel index 6eb3a84e83fce..59dbdb1fa63a6 100644 --- a/packages/kbn-securitysolution-es-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-es-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-es-utils" +PKG_DIRNAME = "kbn-securitysolution-es-utils" PKG_REQUIRE_NAME = "@kbn/securitysolution-es-utils" SOURCE_FILES = glob( @@ -80,7 +80,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -89,9 +89,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-hook-utils/BUILD.bazel b/packages/kbn-securitysolution-hook-utils/BUILD.bazel index 6959bfcc69534..ab33e32a0ad4c 100644 --- a/packages/kbn-securitysolution-hook-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-hook-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-hook-utils" +PKG_DIRNAME = "kbn-securitysolution-hook-utils" PKG_REQUIRE_NAME = "@kbn/securitysolution-hook-utils" SOURCE_FILES = glob( @@ -87,7 +87,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -96,9 +96,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/BUILD.bazel b/packages/kbn-securitysolution-io-ts-alerting-types/BUILD.bazel index 7ddd3ab480bfc..713f56917c19f 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/BUILD.bazel +++ b/packages/kbn-securitysolution-io-ts-alerting-types/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-io-ts-alerting-types" +PKG_DIRNAME = "kbn-securitysolution-io-ts-alerting-types" PKG_REQUIRE_NAME = "@kbn/securitysolution-io-ts-alerting-types" SOURCE_FILES = glob( @@ -90,7 +90,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -99,9 +99,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-io-ts-list-types/BUILD.bazel b/packages/kbn-securitysolution-io-ts-list-types/BUILD.bazel index 7a4388b65053e..718ab4e75c9d8 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/BUILD.bazel +++ b/packages/kbn-securitysolution-io-ts-list-types/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-io-ts-list-types" +PKG_DIRNAME = "kbn-securitysolution-io-ts-list-types" PKG_REQUIRE_NAME = "@kbn/securitysolution-io-ts-list-types" SOURCE_FILES = glob( @@ -91,7 +91,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -100,9 +100,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-io-ts-types/BUILD.bazel b/packages/kbn-securitysolution-io-ts-types/BUILD.bazel index 85f5a05ed6c44..f09e4139fccca 100644 --- a/packages/kbn-securitysolution-io-ts-types/BUILD.bazel +++ b/packages/kbn-securitysolution-io-ts-types/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-io-ts-types" +PKG_DIRNAME = "kbn-securitysolution-io-ts-types" PKG_REQUIRE_NAME = "@kbn/securitysolution-io-ts-types" SOURCE_FILES = glob( @@ -88,7 +88,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -97,9 +97,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel b/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel index 6e8d4de3ccfde..eb30bfe8cc433 100644 --- a/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-io-ts-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-io-ts-utils" +PKG_DIRNAME = "kbn-securitysolution-io-ts-utils" PKG_REQUIRE_NAME = "@kbn/securitysolution-io-ts-utils" SOURCE_FILES = glob( @@ -91,7 +91,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -100,9 +100,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-list-api/BUILD.bazel b/packages/kbn-securitysolution-list-api/BUILD.bazel index 9819e867e3194..39f3f797c569b 100644 --- a/packages/kbn-securitysolution-list-api/BUILD.bazel +++ b/packages/kbn-securitysolution-list-api/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-list-api" +PKG_DIRNAME = "kbn-securitysolution-list-api" PKG_REQUIRE_NAME = "@kbn/securitysolution-list-api" SOURCE_FILES = glob( @@ -90,7 +90,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -99,9 +99,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-list-constants/BUILD.bazel b/packages/kbn-securitysolution-list-constants/BUILD.bazel index 5d4a6c2ffb117..779eef5617de1 100644 --- a/packages/kbn-securitysolution-list-constants/BUILD.bazel +++ b/packages/kbn-securitysolution-list-constants/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-list-constants" +PKG_DIRNAME = "kbn-securitysolution-list-constants" PKG_REQUIRE_NAME = "@kbn/securitysolution-list-constants" SOURCE_FILES = glob( @@ -78,7 +78,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -87,9 +87,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-list-hooks/BUILD.bazel b/packages/kbn-securitysolution-list-hooks/BUILD.bazel index 93a3d0c683dd5..2487cf359d29e 100644 --- a/packages/kbn-securitysolution-list-hooks/BUILD.bazel +++ b/packages/kbn-securitysolution-list-hooks/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-list-hooks" +PKG_DIRNAME = "kbn-securitysolution-list-hooks" PKG_REQUIRE_NAME = "@kbn/securitysolution-list-hooks" SOURCE_FILES = glob( @@ -97,7 +97,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -106,9 +106,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-list-utils/BUILD.bazel b/packages/kbn-securitysolution-list-utils/BUILD.bazel index d1d1a9a3e326a..5155da63bfbc5 100644 --- a/packages/kbn-securitysolution-list-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-list-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-list-utils" +PKG_DIRNAME = "kbn-securitysolution-list-utils" PKG_REQUIRE_NAME = "@kbn/securitysolution-list-utils" SOURCE_FILES = glob( @@ -97,7 +97,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -107,9 +107,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-rules/BUILD.bazel b/packages/kbn-securitysolution-rules/BUILD.bazel index e1da8501dffa1..280c7cd0dae50 100644 --- a/packages/kbn-securitysolution-rules/BUILD.bazel +++ b/packages/kbn-securitysolution-rules/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-rules" +PKG_DIRNAME = "kbn-securitysolution-rules" PKG_REQUIRE_NAME = "@kbn/securitysolution-rules" SOURCE_FILES = glob( @@ -85,7 +85,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -94,9 +94,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-t-grid/BUILD.bazel b/packages/kbn-securitysolution-t-grid/BUILD.bazel index 39c1aff010f88..d907afc660311 100644 --- a/packages/kbn-securitysolution-t-grid/BUILD.bazel +++ b/packages/kbn-securitysolution-t-grid/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-t-grid" +PKG_DIRNAME = "kbn-securitysolution-t-grid" PKG_REQUIRE_NAME = "@kbn/securitysolution-t-grid" SOURCE_FILES = glob( @@ -86,7 +86,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -95,9 +95,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-securitysolution-utils/BUILD.bazel b/packages/kbn-securitysolution-utils/BUILD.bazel index a76553e2fb2c5..68e9ab6dd597b 100644 --- a/packages/kbn-securitysolution-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-securitysolution-utils" +PKG_DIRNAME = "kbn-securitysolution-utils" PKG_REQUIRE_NAME = "@kbn/securitysolution-utils" SOURCE_FILES = glob( @@ -85,7 +85,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -94,9 +94,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ], + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-server-http-tools/BUILD.bazel b/packages/kbn-server-http-tools/BUILD.bazel index 5c73a34ffe5e7..004cfb336f049 100644 --- a/packages/kbn-server-http-tools/BUILD.bazel +++ b/packages/kbn-server-http-tools/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-server-http-tools" +PKG_DIRNAME = "kbn-server-http-tools" PKG_REQUIRE_NAME = "@kbn/server-http-tools" SOURCE_FILES = glob( @@ -89,7 +89,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -98,9 +98,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-server-route-repository/BUILD.bazel b/packages/kbn-server-route-repository/BUILD.bazel index cbe6172e32e40..7ecc92bbe1a26 100644 --- a/packages/kbn-server-route-repository/BUILD.bazel +++ b/packages/kbn-server-route-repository/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-server-route-repository" +PKG_DIRNAME = "kbn-server-route-repository" PKG_REQUIRE_NAME = "@kbn/server-route-repository" SOURCE_FILES = glob( @@ -96,7 +96,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -105,9 +105,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-spec-to-console/BUILD.bazel b/packages/kbn-spec-to-console/BUILD.bazel index ee046c6194f7f..9d41b5762d470 100644 --- a/packages/kbn-spec-to-console/BUILD.bazel +++ b/packages/kbn-spec-to-console/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-spec-to-console" +PKG_DIRNAME = "kbn-spec-to-console" PKG_REQUIRE_NAME = "@kbn/spec-to-console" SOURCE_FILES = glob( @@ -33,7 +33,7 @@ RUNTIME_DEPS = [ ] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -44,9 +44,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-std/BUILD.bazel b/packages/kbn-std/BUILD.bazel index fb59d13596ab7..f92779194187f 100644 --- a/packages/kbn-std/BUILD.bazel +++ b/packages/kbn-std/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-std" +PKG_DIRNAME = "kbn-std" PKG_REQUIRE_NAME = "@kbn/std" SOURCE_FILES = glob( @@ -83,7 +83,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -92,9 +92,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-storybook/BUILD.bazel b/packages/kbn-storybook/BUILD.bazel index c85352b8ac914..e58a4954fd44c 100644 --- a/packages/kbn-storybook/BUILD.bazel +++ b/packages/kbn-storybook/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-storybook" +PKG_DIRNAME = "kbn-storybook" PKG_REQUIRE_NAME = "@kbn/storybook" SOURCE_FILES = glob( @@ -115,7 +115,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -124,9 +124,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-telemetry-tools/BUILD.bazel b/packages/kbn-telemetry-tools/BUILD.bazel index b234f2dd6ea45..d4e2a87075782 100644 --- a/packages/kbn-telemetry-tools/BUILD.bazel +++ b/packages/kbn-telemetry-tools/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-telemetry-tools" +PKG_DIRNAME = "kbn-telemetry-tools" PKG_REQUIRE_NAME = "@kbn/telemetry-tools" SOURCE_FILES = glob( @@ -89,7 +89,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -98,9 +98,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-test-jest-helpers/BUILD.bazel b/packages/kbn-test-jest-helpers/BUILD.bazel index d31f9184cf2ac..6017936b06552 100644 --- a/packages/kbn-test-jest-helpers/BUILD.bazel +++ b/packages/kbn-test-jest-helpers/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@babel/cli:index.bzl", "babel") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-test-jest-helpers" +PKG_DIRNAME = "kbn-test-jest-helpers" PKG_REQUIRE_NAME = "@kbn/test-jest-helpers" SOURCE_FILES = glob( @@ -148,7 +148,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -157,9 +157,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-test/BUILD.bazel b/packages/kbn-test/BUILD.bazel index 1deca3a0f6d07..32eccf2963060 100644 --- a/packages/kbn-test/BUILD.bazel +++ b/packages/kbn-test/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//@babel/cli:index.bzl", "babel") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-test" +PKG_DIRNAME = "kbn-test" PKG_REQUIRE_NAME = "@kbn/test" SOURCE_FILES = glob( @@ -170,7 +170,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -179,9 +179,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js index 3cb0ce86602cd..c13dbb5149f43 100644 --- a/packages/kbn-test/jest-preset.js +++ b/packages/kbn-test/jest-preset.js @@ -113,9 +113,6 @@ module.exports = { `integration_tests/`, ], - // This option allows use of a custom test runner - testRunner: 'jest-circus/runner', - // A map from regular expressions to paths to transformers transform: { '^.+\\.(js|tsx?)$': '/node_modules/@kbn/test/target_node/src/jest/babel_transform.js', diff --git a/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts b/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts index 02e96f62e2488..b7efb33bcd506 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts @@ -13,8 +13,6 @@ import { addSerializer, } from 'jest-snapshot'; import path from 'path'; -import prettier from 'prettier'; -import babelTraverse from '@babel/traverse'; import { once } from 'lodash'; import { Lifecycle } from '../lifecycle'; import { Suite, Test } from '../../fake_mocha_types'; @@ -161,8 +159,8 @@ function getSnapshotState(file: string, updateSnapshot: SnapshotUpdateState) { path.join(dirname + `/__snapshots__/` + filename.replace(path.extname(filename), '.snap')), { updateSnapshot, - getPrettier: () => prettier, - getBabelTraverse: () => babelTraverse, + prettierPath: require.resolve('prettier'), + snapshotFormat: { escapeString: true, printBasicPrototype: true }, } ); diff --git a/packages/kbn-test/src/jest/babel_transform.js b/packages/kbn-test/src/jest/babel_transform.js index 8b25b635bbb13..f2fbbfe00b603 100644 --- a/packages/kbn-test/src/jest/babel_transform.js +++ b/packages/kbn-test/src/jest/babel_transform.js @@ -8,7 +8,7 @@ const babelJest = require('babel-jest'); -module.exports = babelJest.createTransformer({ +module.exports = babelJest.default.createTransformer({ presets: [ [ require.resolve('@kbn/babel-preset/node_preset'), diff --git a/packages/kbn-test/src/jest/configs/get_tests_for_config_paths.ts b/packages/kbn-test/src/jest/configs/get_tests_for_config_paths.ts index 9d0105977a12e..10474413ba297 100644 --- a/packages/kbn-test/src/jest/configs/get_tests_for_config_paths.ts +++ b/packages/kbn-test/src/jest/configs/get_tests_for_config_paths.ts @@ -7,8 +7,8 @@ */ import { readConfig } from 'jest-config'; -import { createContext } from 'jest-runtime'; import { SearchSource } from 'jest'; +import Runtime from 'jest-runtime'; import { asyncMapWithLimit } from '@kbn/std'; const EMPTY_ARGV = { @@ -34,7 +34,7 @@ export async function getTestsForConfigPaths( return await asyncMapWithLimit(configPaths, 60, async (path) => { const config = await readConfig(EMPTY_ARGV, path); const searchSource = new SearchSource( - await createContext(config.projectConfig, { + await Runtime.createContext(config.projectConfig, { maxWorkers: 1, watchman: false, watch: false, diff --git a/packages/kbn-test/src/jest/junit_reporter.ts b/packages/kbn-test/src/jest/junit_reporter.ts index eb5828120a57b..6a1ce9d51ded9 100644 --- a/packages/kbn-test/src/jest/junit_reporter.ts +++ b/packages/kbn-test/src/jest/junit_reporter.ts @@ -60,8 +60,9 @@ export default class JestJUnitReporter extends BaseReporter { ); const msToIso = (ms: number | null | undefined) => - ms ? new Date(ms).toISOString().slice(0, -5) : undefined; - const msToSec = (ms: number | null | undefined) => (ms ? (ms / 1000).toFixed(3) : undefined); + typeof ms === 'number' ? new Date(ms).toISOString().slice(0, -5) : undefined; + const msToSec = (ms: number | null | undefined) => + typeof ms === 'number' ? (ms / 1000).toFixed(3) : undefined; root.att({ name: 'jest', diff --git a/packages/kbn-test/src/jest/run.ts b/packages/kbn-test/src/jest/run.ts index daf4706cebdba..8efcafbec6c87 100644 --- a/packages/kbn-test/src/jest/run.ts +++ b/packages/kbn-test/src/jest/run.ts @@ -20,31 +20,18 @@ import { resolve, relative, sep as osSep } from 'path'; import { existsSync } from 'fs'; import { run } from 'jest'; -import { buildArgv } from 'jest-cli/build/cli'; import { ToolingLog } from '@kbn/tooling-log'; import { getTimeReporter } from '@kbn/ci-stats-reporter'; import { REPO_ROOT } from '@kbn/utils'; import { map } from 'lodash'; +import getopts from 'getopts'; // yarn test:jest src/core/server/saved_objects // yarn test:jest src/core/public/core_system.test.ts // :kibana/src/core/server/saved_objects yarn test:jest -// Patch node 16 types to be compatible with jest 26 -// https://github.com/facebook/jest/issues/11640#issuecomment-893867514 -/* eslint-disable @typescript-eslint/no-namespace,@typescript-eslint/no-empty-interface,no-console */ -declare global { - namespace NodeJS { - interface Global {} - interface InspectOptions {} - - interface ConsoleConstructor extends console.ConsoleConstructor {} - } -} -/* eslint-enable */ - export function runJest(configName = 'jest.config.js') { - const argv = buildArgv(process.argv); + const argv = getopts(process.argv.slice(2)); const devConfigName = 'jest.config.dev.js'; const log = new ToolingLog({ @@ -60,7 +47,7 @@ export function runJest(configName = 'jest.config.js') { const cwd: string = process.env.INIT_CWD || process.cwd(); if (!argv.config) { - testFiles = argv._.splice(2).map((p) => resolve(cwd, p.toString())); + testFiles = argv._.map((p) => resolve(cwd, p.toString())); const commonTestFiles = commonBasePath(testFiles); const testFilesProvided = testFiles.length > 0; diff --git a/packages/kbn-test/src/jest/setup/setup_test.js b/packages/kbn-test/src/jest/setup/setup_test.js index a3eb15a2d2634..b0038daf196c9 100644 --- a/packages/kbn-test/src/jest/setup/setup_test.js +++ b/packages/kbn-test/src/jest/setup/setup_test.js @@ -13,3 +13,9 @@ import 'jest-styled-components'; import '@testing-library/jest-dom'; + +/** + * Removed in Jest 27/jsdom, used in some transitive dependencies + */ +global.setImmediate = require('core-js/stable/set-immediate'); +global.clearImmediate = require('core-js/stable/clear-immediate'); diff --git a/packages/kbn-timelion-grammar/BUILD.bazel b/packages/kbn-timelion-grammar/BUILD.bazel index c906223c2253b..3c7ea13cadf64 100644 --- a/packages/kbn-timelion-grammar/BUILD.bazel +++ b/packages/kbn-timelion-grammar/BUILD.bazel @@ -2,7 +2,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("@npm//peggy:index.bzl", "peggy") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-timelion-grammar" +PKG_DIRNAME = "kbn-timelion-grammar" PKG_REQUIRE_NAME = "@kbn/timelion-grammar" NPM_MODULE_EXTRA_FILES = [ @@ -23,7 +23,7 @@ peggy( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":grammar" ], @@ -33,9 +33,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-tinymath/BUILD.bazel b/packages/kbn-tinymath/BUILD.bazel index ffbd74da2d02e..b8ee25a4973b8 100644 --- a/packages/kbn-tinymath/BUILD.bazel +++ b/packages/kbn-tinymath/BUILD.bazel @@ -2,7 +2,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("@npm//peggy:index.bzl", "peggy") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-tinymath" +PKG_DIRNAME = "kbn-tinymath" PKG_REQUIRE_NAME = "@kbn/tinymath" SOURCE_FILES = glob( @@ -45,7 +45,7 @@ peggy( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ":grammar" @@ -57,9 +57,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-typed-react-router-config/BUILD.bazel b/packages/kbn-typed-react-router-config/BUILD.bazel index c14f2b66b9870..e6f1587e537ed 100644 --- a/packages/kbn-typed-react-router-config/BUILD.bazel +++ b/packages/kbn-typed-react-router-config/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-typed-react-router-config" +PKG_DIRNAME = "kbn-typed-react-router-config" PKG_REQUIRE_NAME = "@kbn/typed-react-router-config" SOURCE_FILES = glob( @@ -100,7 +100,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -109,9 +109,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-ui-framework/BUILD.bazel b/packages/kbn-ui-framework/BUILD.bazel index f38e10eafeec7..2e801955a8524 100644 --- a/packages/kbn-ui-framework/BUILD.bazel +++ b/packages/kbn-ui-framework/BUILD.bazel @@ -1,7 +1,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "pkg_npm") -PKG_BASE_NAME = "kbn-ui-framework" +PKG_DIRNAME = "kbn-ui-framework" PKG_REQUIRE_NAME = "@kbn/ui-framework" SOURCE_FILES = glob([ @@ -23,7 +23,7 @@ NPM_MODULE_EXTRA_FILES = [ RUNTIME_DEPS = [] js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES + [ ":srcs", ], @@ -34,9 +34,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-ui-shared-deps-npm/BUILD.bazel b/packages/kbn-ui-shared-deps-npm/BUILD.bazel index c20613e128e49..7f589c7c0a842 100644 --- a/packages/kbn-ui-shared-deps-npm/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-npm/BUILD.bazel @@ -3,7 +3,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-ui-shared-deps-npm" +PKG_DIRNAME = "kbn-ui-shared-deps-npm" PKG_REQUIRE_NAME = "@kbn/ui-shared-deps-npm" SOURCE_FILES = glob( @@ -154,7 +154,7 @@ webpack( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":shared_built_assets"], package_name = PKG_REQUIRE_NAME, @@ -163,9 +163,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-ui-shared-deps-src/BUILD.bazel b/packages/kbn-ui-shared-deps-src/BUILD.bazel index 4979792e00ee5..0507f18756929 100644 --- a/packages/kbn-ui-shared-deps-src/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-src/BUILD.bazel @@ -3,7 +3,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-ui-shared-deps-src" +PKG_DIRNAME = "kbn-ui-shared-deps-src" PKG_REQUIRE_NAME = "@kbn/ui-shared-deps-src" SOURCE_FILES = glob( @@ -111,7 +111,7 @@ webpack( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":shared_built_assets"], package_name = PKG_REQUIRE_NAME, @@ -120,9 +120,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-ui-theme/BUILD.bazel b/packages/kbn-ui-theme/BUILD.bazel index a004975293a0b..0a890d07fba0f 100644 --- a/packages/kbn-ui-theme/BUILD.bazel +++ b/packages/kbn-ui-theme/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-ui-theme" +PKG_DIRNAME = "kbn-ui-theme" PKG_REQUIRE_NAME = "@kbn/ui-theme" SOURCE_FILES = glob( @@ -80,7 +80,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -89,9 +89,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-user-profile-components/BUILD.bazel b/packages/kbn-user-profile-components/BUILD.bazel index fff27d0f68c34..1037d47a79ad4 100644 --- a/packages/kbn-user-profile-components/BUILD.bazel +++ b/packages/kbn-user-profile-components/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-user-profile-components" +PKG_DIRNAME = "kbn-user-profile-components" PKG_REQUIRE_NAME = "@kbn/user-profile-components" SOURCE_FILES = glob( @@ -87,7 +87,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":target_web"], package_name = PKG_REQUIRE_NAME, @@ -96,9 +96,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-utility-types-jest/BUILD.bazel b/packages/kbn-utility-types-jest/BUILD.bazel index 3b8985767b244..589d17734e55a 100644 --- a/packages/kbn-utility-types-jest/BUILD.bazel +++ b/packages/kbn-utility-types-jest/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-utility-types-jest" +PKG_DIRNAME = "kbn-utility-types-jest" PKG_REQUIRE_NAME = "@kbn/utility-types-jest" SOURCE_FILES = glob( @@ -70,7 +70,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -79,9 +79,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-utility-types/BUILD.bazel b/packages/kbn-utility-types/BUILD.bazel index ad463d9342580..20c640a4b2250 100644 --- a/packages/kbn-utility-types/BUILD.bazel +++ b/packages/kbn-utility-types/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-utility-types" +PKG_DIRNAME = "kbn-utility-types" PKG_REQUIRE_NAME = "@kbn/utility-types" SOURCE_FILES = glob( @@ -74,7 +74,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, @@ -83,9 +83,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/kbn-utils/BUILD.bazel b/packages/kbn-utils/BUILD.bazel index b488b66303910..857ff523a3269 100644 --- a/packages/kbn-utils/BUILD.bazel +++ b/packages/kbn-utils/BUILD.bazel @@ -2,7 +2,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_BASE_NAME = "kbn-utils" +PKG_DIRNAME = "kbn-utils" PKG_REQUIRE_NAME = "@kbn/utils" SOURCE_FILES = glob( @@ -78,7 +78,7 @@ ts_project( ) js_library( - name = PKG_BASE_NAME, + name = PKG_DIRNAME, srcs = NPM_MODULE_EXTRA_FILES, deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, @@ -87,9 +87,7 @@ js_library( pkg_npm( name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] + deps = [":" + PKG_DIRNAME], ) filegroup( diff --git a/packages/shared-ux/storybook/config/BUILD.bazel b/packages/shared-ux/storybook/config/BUILD.bazel index 32e5b6cb440c7..422fe45ee7226 100644 --- a/packages/shared-ux/storybook/config/BUILD.bazel +++ b/packages/shared-ux/storybook/config/BUILD.bazel @@ -62,12 +62,12 @@ RUNTIME_DEPS = [ # # References to NPM packages work the same as RUNTIME_DEPS TYPES_DEPS = [ - "@npm//jest-mock", "//packages/kbn-storybook:npm_module_types", "//packages/kbn-ambient-ui-types:npm_module_types", "//packages/kbn-ambient-storybook-types:npm_module_types", "@npm//@types/node", "@npm//@types/jest", + "@npm//jest-mock", "@npm//@storybook/react", "@npm//@storybook/addon-actions", ] diff --git a/src/core/server/core_app/core_app.test.ts b/src/core/server/core_app/core_app.test.ts index 1ea3eeef29a09..31e4b6176a889 100644 --- a/src/core/server/core_app/core_app.test.ts +++ b/src/core/server/core_app/core_app.test.ts @@ -13,7 +13,7 @@ import { mockRouter } from '@kbn/core-http-router-server-mocks'; import type { UiPlugins } from '@kbn/core-plugins-base-server-internal'; import { coreMock, httpServerMock } from '../mocks'; import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; -import { PluginType } from '../plugins'; +import { PluginType } from '@kbn/core-base-common'; import { CoreApp } from './core_app'; import { RequestHandlerContext } from '..'; diff --git a/src/core/server/core_app/core_app.ts b/src/core/server/core_app/core_app.ts index f0940f6abad50..83665512767e7 100644 --- a/src/core/server/core_app/core_app.ts +++ b/src/core/server/core_app/core_app.ts @@ -22,7 +22,7 @@ import type { } from '@kbn/core-http-server'; import type { UiPlugins } from '@kbn/core-plugins-base-server-internal'; import type { HttpResources, HttpResourcesServiceToolkit } from '@kbn/core-http-resources-server'; -import { InternalCorePreboot, InternalCoreSetup } from '../internal_types'; +import { InternalCorePreboot, InternalCoreSetup } from '@kbn/core-lifecycle-server-internal'; import { registerBundleRoutes } from './bundle_routes'; import type { InternalCoreAppRequestHandlerContext } from './internal_types'; diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 6232a17eb6111..df770c8529ab8 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -29,14 +29,8 @@ */ import { Type } from '@kbn/config-schema'; -import type { DocLinksServiceStart, DocLinksServiceSetup } from '@kbn/core-doc-links-server'; -import type { AppenderConfigType, LoggingServiceSetup } from '@kbn/core-logging-server'; +import type { AppenderConfigType } from '@kbn/core-logging-server'; import { appendersSchema } from '@kbn/core-logging-server-internal'; -import type { - AnalyticsServiceSetup, - AnalyticsServiceStart, - AnalyticsServicePreboot, -} from '@kbn/core-analytics-server'; import type { ExecutionContextSetup, ExecutionContextStart, @@ -46,31 +40,13 @@ import type { RequestHandler, KibanaResponseFactory, RouteMethod, - HttpServicePreboot, HttpServiceSetup, - HttpServiceStart, } from '@kbn/core-http-server'; -import type { PrebootServicePreboot } from '@kbn/core-preboot-server'; -import type { MetricsServiceSetup, MetricsServiceStart } from '@kbn/core-metrics-server'; -import { - ElasticsearchServiceSetup, - ElasticsearchServiceStart, - ElasticsearchServicePreboot, -} from '@kbn/core-elasticsearch-server'; import { configSchema as elasticsearchConfigSchema } from '@kbn/core-elasticsearch-server-internal'; import type { CapabilitiesSetup, CapabilitiesStart } from '@kbn/core-capabilities-server'; -import type { - SavedObjectsServiceSetup, - SavedObjectsServiceStart, -} from '@kbn/core-saved-objects-server'; -import type { DeprecationsServiceSetup } from '@kbn/core-deprecations-server'; -import type { CoreUsageDataStart, CoreUsageDataSetup } from '@kbn/core-usage-data-server'; -import type { I18nServiceSetup } from '@kbn/core-i18n-server'; -import type { StatusServiceSetup } from '@kbn/core-status-server'; -import type { UiSettingsServiceSetup, UiSettingsServiceStart } from '@kbn/core-ui-settings-server'; import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; import type { HttpResources } from '@kbn/core-http-resources-server'; -import { PluginsServiceSetup, PluginsServiceStart } from './plugins'; +import type { PluginsServiceSetup, PluginsServiceStart } from '@kbn/core-plugins-server-internal'; export type { PluginOpaqueId } from '@kbn/core-base-common'; export type { @@ -254,7 +230,6 @@ export type { NodeInfo, NodeRoles } from '@kbn/core-node-server'; export { PluginType } from '@kbn/core-base-common'; export type { - DiscoveredPlugin, PrebootPlugin, Plugin, AsyncPlugin, @@ -263,11 +238,12 @@ export type { PluginInitializer, PluginInitializerContext, PluginManifest, - PluginName, SharedGlobalConfig, MakeUsageFromSchema, ExposedToBrowserDescriptor, -} from './plugins'; +} from '@kbn/core-plugins-server'; + +export type { PluginName, DiscoveredPlugin } from '@kbn/core-base-common'; export type { SavedObject, @@ -467,106 +443,12 @@ export type { PrebootCoreRequestHandlerContext, } from '@kbn/core-http-request-handler-context-server'; -/** - * Context passed to the `setup` method of `preboot` plugins. - * @public - */ -export interface CorePreboot { - /** {@link AnalyticsServicePreboot} */ - analytics: AnalyticsServicePreboot; - /** {@link ElasticsearchServicePreboot} */ - elasticsearch: ElasticsearchServicePreboot; - /** {@link HttpServicePreboot} */ - http: HttpServicePreboot; - /** {@link PrebootServicePreboot} */ - preboot: PrebootServicePreboot; -} - -/** - * Context passed to the `setup` method of `standard` plugins. - * - * @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same - * as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`. - * @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the - * consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`. - * @public - */ -export interface CoreSetup { - /** {@link AnalyticsServiceSetup} */ - analytics: AnalyticsServiceSetup; - /** {@link CapabilitiesSetup} */ - capabilities: CapabilitiesSetup; - /** {@link DocLinksServiceSetup} */ - docLinks: DocLinksServiceSetup; - /** {@link ElasticsearchServiceSetup} */ - elasticsearch: ElasticsearchServiceSetup; - /** {@link ExecutionContextSetup} */ - executionContext: ExecutionContextSetup; - /** {@link HttpServiceSetup} */ - http: HttpServiceSetup & { - /** {@link HttpResources} */ - resources: HttpResources; - }; - /** {@link I18nServiceSetup} */ - i18n: I18nServiceSetup; - /** {@link LoggingServiceSetup} */ - logging: LoggingServiceSetup; - /** {@link MetricsServiceSetup} */ - metrics: MetricsServiceSetup; - /** {@link SavedObjectsServiceSetup} */ - savedObjects: SavedObjectsServiceSetup; - /** {@link StatusServiceSetup} */ - status: StatusServiceSetup; - /** {@link UiSettingsServiceSetup} */ - uiSettings: UiSettingsServiceSetup; - /** {@link DeprecationsServiceSetup} */ - deprecations: DeprecationsServiceSetup; - /** {@link StartServicesAccessor} */ - getStartServices: StartServicesAccessor; - /** @internal {@link CoreUsageDataSetup} */ - coreUsageData: CoreUsageDataSetup; -} - -/** - * Allows plugins to get access to APIs available in start inside async handlers. - * Promise will not resolve until Core and plugin dependencies have completed `start`. - * This should only be used inside handlers registered during `setup` that will only be executed - * after `start` lifecycle. - * - * @public - */ -export type StartServicesAccessor< - TPluginsStart extends object = object, - TStart = unknown -> = () => Promise<[CoreStart, TPluginsStart, TStart]>; - -/** - * Context passed to the plugins `start` method. - * - * @public - */ -export interface CoreStart { - /** {@link AnalyticsServiceStart} */ - analytics: AnalyticsServiceStart; - /** {@link CapabilitiesStart} */ - capabilities: CapabilitiesStart; - /** {@link DocLinksServiceStart} */ - docLinks: DocLinksServiceStart; - /** {@link ElasticsearchServiceStart} */ - elasticsearch: ElasticsearchServiceStart; - /** {@link ExecutionContextStart} */ - executionContext: ExecutionContextStart; - /** {@link HttpServiceStart} */ - http: HttpServiceStart; - /** {@link MetricsServiceStart} */ - metrics: MetricsServiceStart; - /** {@link SavedObjectsServiceStart} */ - savedObjects: SavedObjectsServiceStart; - /** {@link UiSettingsServiceStart} */ - uiSettings: UiSettingsServiceStart; - /** @internal {@link CoreUsageDataStart} */ - coreUsageData: CoreUsageDataStart; -} +export type { + CorePreboot, + CoreSetup, + CoreStart, + StartServicesAccessor, +} from '@kbn/core-lifecycle-server'; export type { CapabilitiesSetup, diff --git a/src/core/server/integration_tests/logging/logging.test.ts b/src/core/server/integration_tests/logging/logging.test.ts index a56449550b3cb..09323239a0ce3 100644 --- a/src/core/server/integration_tests/logging/logging.test.ts +++ b/src/core/server/integration_tests/logging/logging.test.ts @@ -8,7 +8,7 @@ import type { LoggerContextConfigInput } from '@kbn/core-logging-server'; import * as kbnTestServer from '../../../test_helpers/kbn_server'; -import { InternalCoreSetup } from '../../internal_types'; +import { InternalCoreSetup } from '@kbn/core-lifecycle-server-internal'; import { Subject } from 'rxjs'; function createRoot() { diff --git a/src/core/server/integration_tests/plugins/jest.integration.config.js b/src/core/server/integration_tests/plugins/jest.integration.config.js deleted file mode 100644 index 55bbf66147bb8..0000000000000 --- a/src/core/server/integration_tests/plugins/jest.integration.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -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/plugins'], - // 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/plugins/plugins_service.test.ts b/src/core/server/integration_tests/plugins/plugins_service.test.ts deleted file mode 100644 index 2d51b63921bad..0000000000000 --- a/src/core/server/integration_tests/plugins/plugins_service.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -// must be before mocks imports to avoid conflicting with `REPO_ROOT` accessor. -import { REPO_ROOT } from '@kbn/utils'; -import { mockPackage, mockDiscover } from './plugins_service.test.mocks'; - -import { join } from 'path'; - -import { ConfigPath, ConfigService, Env } from '@kbn/config'; -import { getEnvOptions, rawConfigServiceMock } from '@kbn/config-mocks'; -import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; -import { environmentServiceMock } from '@kbn/core-environment-server-mocks'; -import { nodeServiceMock } from '@kbn/core-node-server-mocks'; -import { PluginsService } from '../../plugins/plugins_service'; -import { BehaviorSubject, from } from 'rxjs'; -import { config } from '../../plugins/plugins_config'; -import { coreMock } from '../../mocks'; -import { AsyncPlugin, PluginType } from '../../plugins/types'; -import { PluginWrapper } from '../../plugins/plugin'; - -describe('PluginsService', () => { - const logger = loggingSystemMock.create(); - const environmentPreboot = environmentServiceMock.createPrebootContract(); - const nodePreboot = nodeServiceMock.createInternalPrebootContract(); - let pluginsService: PluginsService; - - const createPlugin = ( - id: string, - { - path = id, - disabled = false, - version = 'some-version', - requiredPlugins = [], - requiredBundles = [], - optionalPlugins = [], - kibanaVersion = '7.0.0', - type = PluginType.standard, - configPath = [path], - server = true, - ui = true, - owner = { name: 'foo' }, - }: { - path?: string; - disabled?: boolean; - version?: string; - requiredPlugins?: string[]; - requiredBundles?: string[]; - optionalPlugins?: string[]; - kibanaVersion?: string; - type?: PluginType; - configPath?: ConfigPath; - server?: boolean; - ui?: boolean; - owner?: { name: string }; - } - ): PluginWrapper => { - return new PluginWrapper({ - path, - manifest: { - id, - version, - configPath: `${configPath}${disabled ? '-disabled' : ''}`, - kibanaVersion, - type, - requiredPlugins, - requiredBundles, - optionalPlugins, - server, - ui, - owner, - }, - opaqueId: Symbol(id), - initializerContext: { logger } as any, - }); - }; - - beforeEach(async () => { - mockPackage.raw = { - branch: 'feature-v1', - version: 'v1', - build: { - distributable: true, - number: 100, - sha: 'feature-v1-build-sha', - }, - }; - - const env = Env.createDefault(REPO_ROOT, getEnvOptions()); - const config$ = new BehaviorSubject>({ - plugins: { - initialize: true, - }, - }); - const rawConfigService = rawConfigServiceMock.create({ rawConfig$: config$ }); - const configService = new ConfigService(rawConfigService, env, logger); - await configService.setSchema(config.path, config.schema); - - pluginsService = new PluginsService({ - coreId: Symbol('core'), - env, - logger, - configService, - }); - }); - - it("properly resolves `getStartServices` in plugin's lifecycle", async () => { - expect.assertions(6); - - const pluginPath = 'plugin-path'; - - mockDiscover.mockReturnValue({ - error$: from([]), - plugin$: from([ - createPlugin('plugin-id', { - path: pluginPath, - configPath: 'path', - }), - ]), - }); - - let startDependenciesResolved = false; - let contextFromStart: any = null; - let contextFromStartService: any = null; - - const pluginStartContract = { - someApi: () => 'foo', - }; - - const pluginInitializer = () => - ({ - setup: async (coreSetup, deps) => { - coreSetup.getStartServices().then(([core, plugins, pluginStart]) => { - startDependenciesResolved = true; - contextFromStartService = { core, plugins, pluginStart }; - }); - }, - start: async (core, plugins) => { - contextFromStart = { core, plugins }; - await new Promise((resolve) => setTimeout(resolve, 10)); - expect(startDependenciesResolved).toBe(false); - return pluginStartContract; - }, - } as AsyncPlugin); - - jest.doMock( - join(pluginPath, 'server'), - () => ({ - plugin: pluginInitializer, - }), - { - virtual: true, - } - ); - - await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot }); - - const prebootDeps = coreMock.createInternalPreboot(); - await pluginsService.preboot(prebootDeps); - - const setupDeps = coreMock.createInternalSetup(); - await pluginsService.setup(setupDeps); - - expect(startDependenciesResolved).toBe(false); - - const startDeps = coreMock.createInternalStart(); - await pluginsService.start(startDeps); - - expect(startDependenciesResolved).toBe(true); - expect(contextFromStart!.core).toEqual(contextFromStartService!.core); - expect(contextFromStart!.plugins).toEqual(contextFromStartService!.plugins); - expect(contextFromStartService!.pluginStart).toEqual(pluginStartContract); - }); -}); diff --git a/src/core/server/integration_tests/saved_objects/migrations/7.7.2_xpack_100k.test.ts b/src/core/server/integration_tests/saved_objects/migrations/7.7.2_xpack_100k.test.ts index 530a4b92ead6a..225faf5e2c275 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/7.7.2_xpack_100k.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/7.7.2_xpack_100k.test.ts @@ -13,7 +13,7 @@ import { Env } from '@kbn/config'; import { getEnvOptions } from '@kbn/config-mocks'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import * as kbnTestServer from '../../../../test_helpers/kbn_server'; -import { InternalCoreStart } from '../../../internal_types'; +import type { InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../../../root'; const kibanaVersion = Env.createDefault(REPO_ROOT, getEnvOptions()).packageInfo.version; diff --git a/src/core/server/integration_tests/saved_objects/migrations/actions/es_errors.test.ts b/src/core/server/integration_tests/saved_objects/migrations/actions/es_errors.test.ts index 749be45b35cb7..164fdb19819db 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/actions/es_errors.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/actions/es_errors.test.ts @@ -7,7 +7,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '../../../..'; -import { InternalCoreStart } from '../../../../internal_types'; +import { InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import * as kbnTestServer from '../../../../../test_helpers/kbn_server'; import { Root } from '../../../../root'; import { diff --git a/src/core/server/integration_tests/saved_objects/migrations/migration_from_older_v1.test.ts b/src/core/server/integration_tests/saved_objects/migrations/migration_from_older_v1.test.ts index b18d20deaa0e6..3663297058b0c 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/migration_from_older_v1.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/migration_from_older_v1.test.ts @@ -16,7 +16,7 @@ import { getEnvOptions } from '@kbn/config-mocks'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; import * as kbnTestServer from '../../../../test_helpers/kbn_server'; -import { InternalCoreStart } from '../../../internal_types'; +import { InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../../../root'; const kibanaVersion = Env.createDefault(REPO_ROOT, getEnvOptions()).packageInfo.version; diff --git a/src/core/server/integration_tests/saved_objects/migrations/migration_from_same_v1.test.ts b/src/core/server/integration_tests/saved_objects/migrations/migration_from_same_v1.test.ts index f7c0cced08f0f..97369305591a6 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/migration_from_same_v1.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/migration_from_same_v1.test.ts @@ -16,7 +16,7 @@ import { getEnvOptions } from '@kbn/config-mocks'; import type { SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; import * as kbnTestServer from '../../../../test_helpers/kbn_server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { InternalCoreStart } from '../../../internal_types'; +import { InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../../../root'; const kibanaVersion = Env.createDefault(REPO_ROOT, getEnvOptions()).packageInfo.version; diff --git a/src/core/server/integration_tests/saved_objects/service/lib/repository.test.ts b/src/core/server/integration_tests/saved_objects/service/lib/repository.test.ts index a8d77abd65baf..d8107b5162f2e 100644 --- a/src/core/server/integration_tests/saved_objects/service/lib/repository.test.ts +++ b/src/core/server/integration_tests/saved_objects/service/lib/repository.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { InternalCoreStart } from '../../../../internal_types'; +import { InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import * as kbnTestServer from '../../../../../test_helpers/kbn_server'; import { Root } from '../../../../root'; diff --git a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts index f0fdc609d8915..6325d80e9588f 100644 --- a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts +++ b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts @@ -11,7 +11,7 @@ import h2o2 from '@hapi/h2o2'; import { URL } from 'url'; import type { SavedObject } from '@kbn/core-saved-objects-common'; import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; -import { InternalCoreSetup, InternalCoreStart } from '../../../../internal_types'; +import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../../../../root'; import * as kbnTestServer from '../../../../../test_helpers/kbn_server'; import { diff --git a/src/core/server/integration_tests/saved_objects/validation/validator.test.ts b/src/core/server/integration_tests/saved_objects/validation/validator.test.ts index 008bebdc5731f..1157bd6c7499b 100644 --- a/src/core/server/integration_tests/saved_objects/validation/validator.test.ts +++ b/src/core/server/integration_tests/saved_objects/validation/validator.test.ts @@ -15,7 +15,7 @@ import { REPO_ROOT } from '@kbn/utils'; import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; import { getEnvOptions } from '@kbn/config-mocks'; -import { InternalCoreSetup, InternalCoreStart } from '../../../internal_types'; +import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../../../root'; import * as kbnTestServer from '../../../../test_helpers/kbn_server'; diff --git a/src/core/server/internal_types.ts b/src/core/server/internal_types.ts deleted file mode 100644 index c66fdf9a968d2..0000000000000 --- a/src/core/server/internal_types.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { DocLinksServiceStart, DocLinksServiceSetup } from '@kbn/core-doc-links-server'; -import { - InternalLoggingServicePreboot, - InternalLoggingServiceSetup, -} from '@kbn/core-logging-server-internal'; -import type { - AnalyticsServicePreboot, - AnalyticsServiceSetup, - AnalyticsServiceStart, -} from '@kbn/core-analytics-server'; -import type { InternalEnvironmentServiceSetup } from '@kbn/core-environment-server-internal'; -import type { - InternalExecutionContextSetup, - InternalExecutionContextStart, -} from '@kbn/core-execution-context-server-internal'; -import type { InternalPrebootServicePreboot } from '@kbn/core-preboot-server-internal'; -import type { - InternalContextPreboot, - InternalContextSetup, -} from '@kbn/core-http-context-server-internal'; -import type { - InternalHttpServicePreboot, - InternalHttpServiceSetup, - InternalHttpServiceStart, -} from '@kbn/core-http-server-internal'; -import type { - InternalMetricsServiceSetup, - InternalMetricsServiceStart, -} from '@kbn/core-metrics-server-internal'; -import { - InternalElasticsearchServicePreboot, - InternalElasticsearchServiceSetup, - InternalElasticsearchServiceStart, -} from '@kbn/core-elasticsearch-server-internal'; -import type { CapabilitiesSetup, CapabilitiesStart } from '@kbn/core-capabilities-server'; -import { - InternalSavedObjectsServiceSetup, - InternalSavedObjectsServiceStart, -} from '@kbn/core-saved-objects-server-internal'; -import { - InternalDeprecationsServiceSetup, - InternalDeprecationsServiceStart, -} from '@kbn/core-deprecations-server-internal'; -import type { CoreUsageDataStart } from '@kbn/core-usage-data-server'; -import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; -import type { I18nServiceSetup } from '@kbn/core-i18n-server'; -import type { InternalStatusServiceSetup } from '@kbn/core-status-server-internal'; -import type { - InternalUiSettingsServicePreboot, - InternalUiSettingsServiceSetup, - InternalUiSettingsServiceStart, -} from '@kbn/core-ui-settings-server-internal'; -import type { InternalRenderingServiceSetup } from '@kbn/core-rendering-server-internal'; -import type { - InternalHttpResourcesPreboot, - InternalHttpResourcesSetup, -} from '@kbn/core-http-resources-server-internal'; - -/** @internal */ -export interface InternalCorePreboot { - analytics: AnalyticsServicePreboot; - context: InternalContextPreboot; - http: InternalHttpServicePreboot; - elasticsearch: InternalElasticsearchServicePreboot; - uiSettings: InternalUiSettingsServicePreboot; - httpResources: InternalHttpResourcesPreboot; - logging: InternalLoggingServicePreboot; - preboot: InternalPrebootServicePreboot; -} - -/** @internal */ -export interface InternalCoreSetup { - analytics: AnalyticsServiceSetup; - capabilities: CapabilitiesSetup; - context: InternalContextSetup; - docLinks: DocLinksServiceSetup; - http: InternalHttpServiceSetup; - elasticsearch: InternalElasticsearchServiceSetup; - executionContext: InternalExecutionContextSetup; - i18n: I18nServiceSetup; - savedObjects: InternalSavedObjectsServiceSetup; - status: InternalStatusServiceSetup; - uiSettings: InternalUiSettingsServiceSetup; - environment: InternalEnvironmentServiceSetup; - rendering: InternalRenderingServiceSetup; - httpResources: InternalHttpResourcesSetup; - logging: InternalLoggingServiceSetup; - metrics: InternalMetricsServiceSetup; - deprecations: InternalDeprecationsServiceSetup; - coreUsageData: InternalCoreUsageDataSetup; -} - -/** - * @internal - */ -export interface InternalCoreStart { - analytics: AnalyticsServiceStart; - capabilities: CapabilitiesStart; - elasticsearch: InternalElasticsearchServiceStart; - docLinks: DocLinksServiceStart; - http: InternalHttpServiceStart; - metrics: InternalMetricsServiceStart; - savedObjects: InternalSavedObjectsServiceStart; - uiSettings: InternalUiSettingsServiceStart; - coreUsageData: CoreUsageDataStart; - executionContext: InternalExecutionContextStart; - deprecations: InternalDeprecationsServiceStart; -} diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index 356fd4deb44d6..028465ebfb8ac 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -10,38 +10,16 @@ import { of } from 'rxjs'; import { duration } from 'moment'; import { ByteSizeValue } from '@kbn/config-schema'; import { isPromise } from '@kbn/std'; -import type { MockedKeys } from '@kbn/utility-types-jest'; -import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; -import { loggingSystemMock, loggingServiceMock } from '@kbn/core-logging-server-mocks'; -import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; -import { environmentServiceMock } from '@kbn/core-environment-server-mocks'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { nodeServiceMock } from '@kbn/core-node-server-mocks'; -import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; -import { prebootServiceMock } from '@kbn/core-preboot-server-mocks'; -import { contextServiceMock } from '@kbn/core-http-context-server-mocks'; -import { httpServiceMock } from '@kbn/core-http-server-mocks'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; -import { metricsServiceMock } from '@kbn/core-metrics-server-mocks'; -import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks'; import { typeRegistryMock as savedObjectsTypeRegistryMock } from '@kbn/core-saved-objects-base-server-mocks'; import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks'; -import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks'; -import { i18nServiceMock } from '@kbn/core-i18n-server-mocks'; -import { statusServiceMock } from '@kbn/core-status-server-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; -import { renderingServiceMock } from '@kbn/core-rendering-server-mocks'; -import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; -import type { - PluginInitializerContext, - CoreSetup, - CoreStart, - StartServicesAccessor, - CorePreboot, - RequestHandlerContext, -} from '.'; -import { SharedGlobalConfig } from './plugins'; +import { coreLifecycleMock, coreInternalLifecycleMock } from '@kbn/core-lifecycle-server-mocks'; +import type { SharedGlobalConfig, PluginInitializerContext } from '@kbn/core-plugins-server'; export { configServiceMock, configDeprecationsMock } from '@kbn/config-mocks'; export { loggingSystemMock } from '@kbn/core-logging-server-mocks'; @@ -132,139 +110,6 @@ function pluginInitializerContextMock(config: T = {} as T) { return mock; } -type CorePrebootMockType = MockedKeys & { - elasticsearch: ReturnType; -}; - -function createCorePrebootMock() { - const mock: CorePrebootMockType = { - analytics: analyticsServiceMock.createAnalyticsServicePreboot(), - elasticsearch: elasticsearchServiceMock.createPreboot(), - http: httpServiceMock.createPrebootContract() as CorePrebootMockType['http'], - preboot: prebootServiceMock.createPrebootContract(), - }; - - return mock; -} - -type CoreSetupMockType = MockedKeys & { - elasticsearch: ReturnType; - getStartServices: jest.MockedFunction>; -}; - -function createCoreSetupMock({ - pluginStartDeps = {}, - pluginStartContract, -}: { - pluginStartDeps?: object; - pluginStartContract?: any; -} = {}) { - const httpMock: jest.Mocked = { - ...httpServiceMock.createSetupContract(), - resources: httpResourcesMock.createRegistrar(), - }; - - const uiSettingsMock = { - register: uiSettingsServiceMock.createSetupContract().register, - }; - - const mock: CoreSetupMockType = { - analytics: analyticsServiceMock.createAnalyticsServiceSetup(), - capabilities: capabilitiesServiceMock.createSetupContract(), - docLinks: docLinksServiceMock.createSetupContract(), - elasticsearch: elasticsearchServiceMock.createSetup(), - http: httpMock, - i18n: i18nServiceMock.createSetupContract(), - savedObjects: savedObjectsServiceMock.createInternalSetupContract(), - status: statusServiceMock.createSetupContract(), - uiSettings: uiSettingsMock, - logging: loggingServiceMock.createSetupContract(), - metrics: metricsServiceMock.createSetupContract(), - deprecations: deprecationsServiceMock.createSetupContract(), - executionContext: executionContextServiceMock.createInternalSetupContract(), - coreUsageData: { - registerUsageCounter: coreUsageDataServiceMock.createSetupContract().registerUsageCounter, - }, - getStartServices: jest - .fn, object, any]>, []>() - .mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]), - }; - - return mock; -} - -function createCoreStartMock() { - const mock: MockedKeys = { - analytics: analyticsServiceMock.createAnalyticsServiceStart(), - capabilities: capabilitiesServiceMock.createStartContract(), - docLinks: docLinksServiceMock.createStartContract(), - elasticsearch: elasticsearchServiceMock.createStart(), - http: httpServiceMock.createStartContract(), - metrics: metricsServiceMock.createStartContract(), - savedObjects: savedObjectsServiceMock.createStartContract(), - uiSettings: uiSettingsServiceMock.createStartContract(), - coreUsageData: coreUsageDataServiceMock.createStartContract(), - executionContext: executionContextServiceMock.createInternalStartContract(), - }; - - return mock; -} - -function createInternalCorePrebootMock() { - const prebootDeps = { - analytics: analyticsServiceMock.createAnalyticsServicePreboot(), - context: contextServiceMock.createPrebootContract(), - elasticsearch: elasticsearchServiceMock.createInternalPreboot(), - http: httpServiceMock.createInternalPrebootContract(), - httpResources: httpResourcesMock.createPrebootContract(), - uiSettings: uiSettingsServiceMock.createPrebootContract(), - logging: loggingServiceMock.createInternalPrebootContract(), - preboot: prebootServiceMock.createInternalPrebootContract(), - }; - return prebootDeps; -} - -function createInternalCoreSetupMock() { - const setupDeps = { - analytics: analyticsServiceMock.createAnalyticsServiceSetup(), - capabilities: capabilitiesServiceMock.createSetupContract(), - context: contextServiceMock.createSetupContract(), - docLinks: docLinksServiceMock.createSetupContract(), - elasticsearch: elasticsearchServiceMock.createInternalSetup(), - http: httpServiceMock.createInternalSetupContract(), - savedObjects: savedObjectsServiceMock.createInternalSetupContract(), - status: statusServiceMock.createInternalSetupContract(), - environment: environmentServiceMock.createSetupContract(), - i18n: i18nServiceMock.createSetupContract(), - httpResources: httpResourcesMock.createSetupContract(), - rendering: renderingServiceMock.createSetupContract(), - uiSettings: uiSettingsServiceMock.createSetupContract(), - logging: loggingServiceMock.createInternalSetupContract(), - metrics: metricsServiceMock.createInternalSetupContract(), - deprecations: deprecationsServiceMock.createInternalSetupContract(), - executionContext: executionContextServiceMock.createInternalSetupContract(), - coreUsageData: coreUsageDataServiceMock.createSetupContract(), - }; - return setupDeps; -} - -function createInternalCoreStartMock() { - const startDeps = { - analytics: analyticsServiceMock.createAnalyticsServiceStart(), - capabilities: capabilitiesServiceMock.createStartContract(), - docLinks: docLinksServiceMock.createStartContract(), - elasticsearch: elasticsearchServiceMock.createInternalStart(), - http: httpServiceMock.createInternalStartContract(), - metrics: metricsServiceMock.createInternalStartContract(), - savedObjects: savedObjectsServiceMock.createInternalStartContract(), - uiSettings: uiSettingsServiceMock.createStartContract(), - coreUsageData: coreUsageDataServiceMock.createStartContract(), - executionContext: executionContextServiceMock.createInternalStartContract(), - deprecations: deprecationsServiceMock.createInternalStartContract(), - }; - return startDeps; -} - function createCoreRequestHandlerContextMock() { return { savedObjects: { @@ -321,12 +166,12 @@ const createCustomRequestHandlerContextMock = (contextParts: T): CustomReques }; export const coreMock = { - createPreboot: createCorePrebootMock, - createSetup: createCoreSetupMock, - createStart: createCoreStartMock, - createInternalPreboot: createInternalCorePrebootMock, - createInternalSetup: createInternalCoreSetupMock, - createInternalStart: createInternalCoreStartMock, + createPreboot: coreLifecycleMock.createPreboot, + createSetup: coreLifecycleMock.createCoreSetup, + createStart: coreLifecycleMock.createCoreStart, + createInternalPreboot: coreInternalLifecycleMock.createInternalPreboot, + createInternalSetup: coreInternalLifecycleMock.createInternalSetup, + createInternalStart: coreInternalLifecycleMock.createInternalStart, createPluginInitializerContext: pluginInitializerContextMock, createRequestHandlerContext: createCoreRequestHandlerContextMock, createCustomRequestHandlerContext: createCustomRequestHandlerContextMock, diff --git a/src/core/server/root/elastic_config.ts b/src/core/server/root/elastic_config.ts new file mode 100644 index 0000000000000..84b2ce394962a --- /dev/null +++ b/src/core/server/root/elastic_config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { apmConfigSchema } from '@kbn/apm-config-loader'; +import type { ServiceConfigDescriptor } from '@kbn/core-base-server-internal'; + +const elasticConfig = schema.object({ + apm: apmConfigSchema, +}); + +export type ElasticConfigType = TypeOf; + +export const elasticApmConfig: ServiceConfigDescriptor = { + path: 'elastic', + schema: elasticConfig, +}; diff --git a/src/core/server/root/index.ts b/src/core/server/root/index.ts index 2f3bcce039849..e4a129188ea6b 100644 --- a/src/core/server/root/index.ts +++ b/src/core/server/root/index.ts @@ -7,10 +7,20 @@ */ import { ConnectableObservable, Subscription } from 'rxjs'; -import { first, publishReplay, switchMap, concatMap, tap } from 'rxjs/operators'; +import { + first, + publishReplay, + switchMap, + concatMap, + tap, + distinctUntilChanged, +} from 'rxjs/operators'; import type { Logger, LoggerFactory } from '@kbn/logging'; import { Env, RawConfigurationProvider } from '@kbn/config'; import { LoggingConfigType, LoggingSystem } from '@kbn/core-logging-server-internal'; +import apm from 'elastic-apm-node'; +import { isEqual } from 'lodash'; +import type { ElasticConfigType } from './elastic_config'; import { Server } from '../server'; /** @@ -22,6 +32,7 @@ export class Root { private readonly loggingSystem: LoggingSystem; private readonly server: Server; private loggingConfigSubscription?: Subscription; + private apmConfigSubscription?: Subscription; constructor( rawConfigProvider: RawConfigurationProvider, @@ -37,7 +48,9 @@ export class Root { public async preboot() { try { this.server.setupCoreConfig(); + this.setupApmLabelSync(); await this.setupLogging(); + this.log.debug('prebooting root'); return await this.server.preboot(); } catch (e) { @@ -85,6 +98,10 @@ export class Root { this.loggingConfigSubscription.unsubscribe(); this.loggingConfigSubscription = undefined; } + if (this.apmConfigSubscription !== undefined) { + this.apmConfigSubscription.unsubscribe(); + this.apmConfigSubscription = undefined; + } await this.loggingSystem.stop(); if (this.onShutdown !== undefined) { @@ -92,6 +109,23 @@ export class Root { } } + private setupApmLabelSync() { + const { configService } = this.server; + + // Update APM labels on config change + this.apmConfigSubscription = configService + .getConfig$() + .pipe( + switchMap(() => configService.atPath('elastic')), + distinctUntilChanged(isEqual), + tap((elasticConfig) => { + const labels = elasticConfig.apm?.globalLabels || {}; + apm.addLabels(labels); + }) + ) + .subscribe(); + } + private async setupLogging() { const { configService } = this.server; // Stream that maps config updates to logger updates, including update failures. diff --git a/src/core/server/server.test.mocks.ts b/src/core/server/server.test.mocks.ts index 3e1d5c0e3a28f..01f856f6b3a89 100644 --- a/src/core/server/server.test.mocks.ts +++ b/src/core/server/server.test.mocks.ts @@ -13,10 +13,10 @@ jest.doMock('@kbn/core-http-server-internal', () => ({ HttpService: jest.fn(() => mockHttpService), })); -import { pluginServiceMock } from './plugins/plugins_service.mock'; +import { pluginServiceMock } from '@kbn/core-plugins-server-mocks'; export const mockPluginsService = pluginServiceMock.create(); -jest.doMock('./plugins/plugins_service', () => ({ +jest.doMock('@kbn/core-plugins-server-internal', () => ({ PluginsService: jest.fn(() => mockPluginsService), })); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 0949b9ee65f8a..1f60c3242215a 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -69,10 +69,18 @@ import type { import { RenderingService } from '@kbn/core-rendering-server-internal'; import { HttpResourcesService } from '@kbn/core-http-resources-server-internal'; +import { + InternalCorePreboot, + InternalCoreSetup, + InternalCoreStart, +} from '@kbn/core-lifecycle-server-internal'; +import { + DiscoveredPlugins, + PluginsService, + config as pluginsConfig, +} from '@kbn/core-plugins-server-internal'; import { CoreApp } from './core_app'; -import { PluginsService, config as pluginsConfig } from './plugins'; -import { InternalCorePreboot, InternalCoreSetup, InternalCoreStart } from './internal_types'; -import { DiscoveredPlugins } from './plugins'; +import { elasticApmConfig } from './root/elastic_config'; const coreId = Symbol('core'); const rootConfigPath = ''; @@ -450,6 +458,7 @@ export class Server { cspConfig, deprecationConfig, elasticsearchConfig, + elasticApmConfig, executionContextConfig, externalUrlConfig, httpConfig, diff --git a/src/core/test_helpers/kbn_server.ts b/src/core/test_helpers/kbn_server.ts index faa45c52d84b8..64c32c47ca2a9 100644 --- a/src/core/test_helpers/kbn_server.ts +++ b/src/core/test_helpers/kbn_server.ts @@ -21,7 +21,7 @@ import { } from '@kbn/test'; import { CliArgs, Env } from '@kbn/config'; -import { InternalCoreSetup, InternalCoreStart } from '../server/internal_types'; +import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-server-internal'; import { Root } from '../server/root'; export type HttpMethod = 'delete' | 'get' | 'head' | 'post' | 'put' | 'patch'; diff --git a/src/plugins/bfetch/common/buffer/tests/timed_item_buffer.test.ts b/src/plugins/bfetch/common/buffer/tests/timed_item_buffer.test.ts index 22d3fb2a44689..377ae064a439c 100644 --- a/src/plugins/bfetch/common/buffer/tests/timed_item_buffer.test.ts +++ b/src/plugins/bfetch/common/buffer/tests/timed_item_buffer.test.ts @@ -9,7 +9,7 @@ import { TimedItemBuffer } from '../timed_item_buffer'; import { runItemBufferTests } from './run_item_buffer_tests'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); beforeEach(() => { jest.clearAllTimers(); diff --git a/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts b/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts index 14fccf09d83b0..d3aaaf256f2eb 100644 --- a/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts +++ b/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts @@ -11,7 +11,8 @@ import { fetchStreaming as fetchStreamingReal } from '../streaming/fetch_streami import { AbortError, defer, of } from '@kbn/kibana-utils-plugin/public'; import { Subject } from 'rxjs'; -const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); +const flushPromises = () => + new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); const getPromiseState = (promise: Promise): Promise<'resolved' | 'rejected' | 'pending'> => Promise.race<'resolved' | 'rejected' | 'pending'>([ @@ -50,7 +51,7 @@ const setup = () => { describe('createStreamingBatchedFunction()', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx index ed8c87b5df147..10636f452004d 100644 --- a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx @@ -115,7 +115,9 @@ function EditorUI({ initialTextValue, setEditorInstance }: EditorProps) { const loadBufferFromRemote = (url: string) => { const coreEditor = editor.getCoreEditor(); - if (/^https?:\/\//.test(url)) { + // Normalize and encode the URL to avoid issues with spaces and other special characters. + const encodedUrl = new URL(url).toString(); + if (/^https?:\/\//.test(encodedUrl)) { const loadFrom: Record = { url, // Having dataType here is required as it doesn't allow jQuery to `eval` content diff --git a/src/plugins/controls/common/control_group/control_group_panel_diff_system.ts b/src/plugins/controls/common/control_group/control_group_panel_diff_system.ts new file mode 100644 index 0000000000000..0ef2438494d7e --- /dev/null +++ b/src/plugins/controls/common/control_group/control_group_panel_diff_system.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import deepEqual from 'fast-deep-equal'; +import { omit, isEqual } from 'lodash'; +import { OptionsListEmbeddableInput, OPTIONS_LIST_CONTROL } from '../options_list/types'; + +import { ControlPanelState } from './types'; + +interface DiffSystem { + getPanelIsEqual: (initialInput: ControlPanelState, newInput: ControlPanelState) => boolean; +} + +export const genericControlPanelDiffSystem: DiffSystem = { + getPanelIsEqual: (initialInput, newInput) => { + return deepEqual(initialInput, newInput); + }, +}; + +export const ControlPanelDiffSystems: { + [key: string]: DiffSystem; +} = { + [OPTIONS_LIST_CONTROL]: { + getPanelIsEqual: (initialInput, newInput) => { + if (!deepEqual(omit(initialInput, 'explicitInput'), omit(newInput, 'explicitInput'))) { + return false; + } + + const { + exclude: excludeA, + selectedOptions: selectedA, + singleSelect: singleSelectA, + hideExclude: hideExcludeA, + runPastTimeout: runPastTimeoutA, + ...inputA + }: Partial = initialInput.explicitInput; + const { + exclude: excludeB, + selectedOptions: selectedB, + singleSelect: singleSelectB, + hideExclude: hideExcludeB, + runPastTimeout: runPastTimeoutB, + ...inputB + }: Partial = newInput.explicitInput; + + return ( + Boolean(excludeA) === Boolean(excludeB) && + Boolean(singleSelectA) === Boolean(singleSelectB) && + Boolean(hideExcludeA) === Boolean(hideExcludeB) && + Boolean(runPastTimeoutA) === Boolean(runPastTimeoutB) && + isEqual(selectedA ?? [], selectedB ?? []) && + deepEqual(inputA, inputB) + ); + }, + }, +}; diff --git a/src/plugins/controls/common/control_group/control_group_persistence.ts b/src/plugins/controls/common/control_group/control_group_persistence.ts index 16c06297b6fde..1dbe096307c50 100644 --- a/src/plugins/controls/common/control_group/control_group_persistence.ts +++ b/src/plugins/controls/common/control_group/control_group_persistence.ts @@ -9,7 +9,7 @@ import { SerializableRecord } from '@kbn/utility-types'; import deepEqual from 'fast-deep-equal'; -import { pick } from 'lodash'; +import { pick, omit, xor } from 'lodash'; import { ControlGroupInput } from '..'; import { DEFAULT_CONTROL_GROW, @@ -17,6 +17,10 @@ import { DEFAULT_CONTROL_WIDTH, } from './control_group_constants'; import { PersistableControlGroupInput, RawControlGroupAttributes } from './types'; +import { + ControlPanelDiffSystems, + genericControlPanelDiffSystem, +} from './control_group_panel_diff_system'; const safeJSONParse = (jsonString?: string): OutType | undefined => { if (!jsonString && typeof jsonString !== 'string') return; @@ -54,10 +58,40 @@ export const persistableControlGroupInputIsEqual = ( ...defaultInput, ...pick(b, ['panels', 'chainingSystem', 'controlStyle', 'ignoreParentSettings']), }; - if (deepEqual(inputA, inputB)) return true; + + if ( + getPanelsAreEqual(inputA.panels, inputB.panels) && + deepEqual(omit(inputA, 'panels'), omit(inputB, 'panels')) + ) + return true; + return false; }; +const getPanelsAreEqual = ( + originalPanels: PersistableControlGroupInput['panels'], + newPanels: PersistableControlGroupInput['panels'] +) => { + const originalPanelIds = Object.keys(originalPanels); + const newPanelIds = Object.keys(newPanels); + const panelIdDiff = xor(originalPanelIds, newPanelIds); + if (panelIdDiff.length > 0) { + return false; + } + + for (const panelId of newPanelIds) { + const newPanelType = newPanels[panelId].type; + const panelIsEqual = ControlPanelDiffSystems[newPanelType] + ? ControlPanelDiffSystems[newPanelType].getPanelIsEqual( + originalPanels[panelId], + newPanels[panelId] + ) + : genericControlPanelDiffSystem.getPanelIsEqual(originalPanels[panelId], newPanels[panelId]); + if (!panelIsEqual) return false; + } + return true; +}; + export const controlGroupInputToRawControlGroupAttributes = ( controlGroupInput: Omit ): RawControlGroupAttributes => { diff --git a/src/plugins/controls/common/options_list/mocks.tsx b/src/plugins/controls/common/options_list/mocks.tsx index 09f6d9caa33b4..ccbe3a1132479 100644 --- a/src/plugins/controls/common/options_list/mocks.tsx +++ b/src/plugins/controls/common/options_list/mocks.tsx @@ -28,6 +28,8 @@ const mockOptionsListEmbeddableInput = { selectedOptions: [], runPastTimeout: false, singleSelect: false, + allowExclude: false, + exclude: false, } as OptionsListEmbeddableInput; const mockOptionsListOutput = { diff --git a/src/plugins/controls/common/options_list/types.ts b/src/plugins/controls/common/options_list/types.ts index 25db6c50349c4..59b78ee38d0b9 100644 --- a/src/plugins/controls/common/options_list/types.ts +++ b/src/plugins/controls/common/options_list/types.ts @@ -17,6 +17,8 @@ export interface OptionsListEmbeddableInput extends DataControlInput { selectedOptions?: string[]; runPastTimeout?: boolean; singleSelect?: boolean; + hideExclude?: boolean; + exclude?: boolean; } export type OptionsListField = FieldSpec & { diff --git a/src/plugins/controls/public/options_list/components/options_list_control.tsx b/src/plugins/controls/public/options_list/components/options_list_control.tsx index 7eb8fe783cc0b..93bf0cbef864e 100644 --- a/src/plugins/controls/public/options_list/components/options_list_control.tsx +++ b/src/plugins/controls/public/options_list/components/options_list_control.tsx @@ -11,7 +11,13 @@ import classNames from 'classnames'; import { debounce, isEmpty } from 'lodash'; import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; -import { EuiFilterButton, EuiFilterGroup, EuiPopover, useResizeObserver } from '@elastic/eui'; +import { + EuiFilterButton, + EuiFilterGroup, + EuiPopover, + EuiTextColor, + useResizeObserver, +} from '@elastic/eui'; import { useReduxEmbeddableContext } from '@kbn/presentation-util-plugin/public'; import { OptionsListStrings } from './options_list_strings'; @@ -43,6 +49,7 @@ export const OptionsListControl = ({ typeaheadSubject }: { typeaheadSubject: Sub const controlStyle = select((state) => state.explicitInput.controlStyle); const singleSelect = select((state) => state.explicitInput.singleSelect); const id = select((state) => state.explicitInput.id); + const exclude = select((state) => state.explicitInput.exclude); const loading = select((state) => state.output.loading); @@ -75,6 +82,11 @@ export const OptionsListControl = ({ typeaheadSubject }: { typeaheadSubject: Sub validSelectionsCount: validSelections?.length, selectionDisplayNode: ( <> + {exclude && ( + + {OptionsListStrings.control.getNegate()}{' '} + + )} {validSelections && ( {validSelections?.join(OptionsListStrings.control.getSeparator())} )} @@ -86,7 +98,7 @@ export const OptionsListControl = ({ typeaheadSubject }: { typeaheadSubject: Sub ), }; - }, [validSelections, invalidSelections]); + }, [exclude, validSelections, invalidSelections]); const button = (
diff --git a/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx b/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx index 0cd96232b714e..0723fcaad6ba6 100644 --- a/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx +++ b/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx @@ -8,7 +8,8 @@ import React, { useState } from 'react'; -import { EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip, EuiSwitch } from '@elastic/eui'; +import { css } from '@emotion/react'; import { OptionsListStrings } from './options_list_strings'; import { ControlEditorProps, OptionsListEmbeddableInput } from '../..'; @@ -16,6 +17,7 @@ import { ControlEditorProps, OptionsListEmbeddableInput } from '../..'; interface OptionsListEditorState { singleSelect?: boolean; runPastTimeout?: boolean; + hideExclude?: boolean; } export const OptionsListEditorOptions = ({ @@ -25,6 +27,7 @@ export const OptionsListEditorOptions = ({ const [state, setState] = useState({ singleSelect: initialInput?.singleSelect, runPastTimeout: initialInput?.runPastTimeout, + hideExclude: initialInput?.hideExclude, }); return ( @@ -41,14 +44,40 @@ export const OptionsListEditorOptions = ({ { - onChange({ runPastTimeout: !state.runPastTimeout }); - setState((s) => ({ ...s, runPastTimeout: !s.runPastTimeout })); + onChange({ hideExclude: !state.hideExclude }); + setState((s) => ({ ...s, hideExclude: !s.hideExclude })); + if (initialInput?.exclude) onChange({ exclude: false }); }} /> + + + + { + onChange({ runPastTimeout: !state.runPastTimeout }); + setState((s) => ({ ...s, runPastTimeout: !s.runPastTimeout })); + }} + /> + + + + + + ); }; diff --git a/src/plugins/controls/public/options_list/components/options_list_popover.test.tsx b/src/plugins/controls/public/options_list/components/options_list_popover.test.tsx index f30d9a785ffec..eca6fe72376a1 100644 --- a/src/plugins/controls/public/options_list/components/options_list_popover.test.tsx +++ b/src/plugins/controls/public/options_list/components/options_list_popover.test.tsx @@ -97,4 +97,22 @@ describe('Options list popover', () => { expect(child.text()).toBe(selections[i]); }); }); + + test('should default to exclude = false', () => { + const popover = mountComponent(); + const includeButton = findTestSubject(popover, 'optionsList__includeResults'); + const excludeButton = findTestSubject(popover, 'optionsList__excludeResults'); + expect(includeButton.prop('checked')).toBe(true); + expect(excludeButton.prop('checked')).toBeFalsy(); + }); + + test('if exclude = true, select appropriate button in button group', () => { + const popover = mountComponent({ + explicitInput: { exclude: true }, + }); + const includeButton = findTestSubject(popover, 'optionsList__includeResults'); + const excludeButton = findTestSubject(popover, 'optionsList__excludeResults'); + expect(includeButton.prop('checked')).toBeFalsy(); + expect(excludeButton.prop('checked')).toBe(true); + }); }); diff --git a/src/plugins/controls/public/options_list/components/options_list_popover.tsx b/src/plugins/controls/public/options_list/components/options_list_popover.tsx index 8863a3d1978a3..48be0d9253285 100644 --- a/src/plugins/controls/public/options_list/components/options_list_popover.tsx +++ b/src/plugins/controls/public/options_list/components/options_list_popover.tsx @@ -22,7 +22,11 @@ import { EuiBadge, EuiIcon, EuiTitle, + EuiPopoverFooter, + EuiButtonGroup, + useEuiBackgroundColor, } from '@elastic/eui'; +import { css } from '@emotion/react'; import { useReduxEmbeddableContext } from '@kbn/presentation-util-plugin/public'; import { optionsListReducers } from '../options_list_reducers'; @@ -34,12 +38,23 @@ export interface OptionsListPopoverProps { updateSearchString: (newSearchString: string) => void; } +const aggregationToggleButtons = [ + { + id: 'optionsList__includeResults', + label: OptionsListStrings.popover.getIncludeLabel(), + }, + { + id: 'optionsList__excludeResults', + label: OptionsListStrings.popover.getExcludeLabel(), + }, +]; + export const OptionsListPopover = ({ width, updateSearchString }: OptionsListPopoverProps) => { // Redux embeddable container Context const { useEmbeddableDispatch, useEmbeddableSelector: select, - actions: { selectOption, deselectOption, clearSelections, replaceSelection }, + actions: { selectOption, deselectOption, clearSelections, replaceSelection, setExclude }, } = useReduxEmbeddableContext(); const dispatch = useEmbeddableDispatch(); @@ -52,8 +67,10 @@ export const OptionsListPopover = ({ width, updateSearchString }: OptionsListPop const field = select((state) => state.componentState.field); const selectedOptions = select((state) => state.explicitInput.selectedOptions); + const hideExclude = select((state) => state.explicitInput.hideExclude); const singleSelect = select((state) => state.explicitInput.singleSelect); const title = select((state) => state.explicitInput.title); + const exclude = select((state) => state.explicitInput.exclude); const loading = select((state) => state.output.loading); @@ -65,6 +82,7 @@ export const OptionsListPopover = ({ width, updateSearchString }: OptionsListPop ); const [showOnlySelected, setShowOnlySelected] = useState(false); + const euiBackgroundColor = useEuiBackgroundColor('subdued'); return ( <> @@ -77,6 +95,7 @@ export const OptionsListPopover = ({ width, updateSearchString }: OptionsListPop direction="row" justifyContent="spaceBetween" alignItems="center" + responsive={false} > )}
+ {!hideExclude && ( + + + dispatch(setExclude(optionId === 'optionsList__excludeResults')) + } + buttonSize="compressed" + data-test-subj="optionsList__includeExcludeButtonGroup" + /> + + )} ); }; diff --git a/src/plugins/controls/public/options_list/components/options_list_strings.ts b/src/plugins/controls/public/options_list/components/options_list_strings.ts index 8e3d55ae6b764..cfab9633b81e9 100644 --- a/src/plugins/controls/public/options_list/components/options_list_strings.ts +++ b/src/plugins/controls/public/options_list/components/options_list_strings.ts @@ -18,6 +18,10 @@ export const OptionsListStrings = { i18n.translate('controls.optionsList.control.placeholder', { defaultMessage: 'Any', }), + getNegate: () => + i18n.translate('controls.optionsList.control.negate', { + defaultMessage: 'NOT', + }), }, editor: { getAllowMultiselectTitle: () => @@ -26,7 +30,16 @@ export const OptionsListStrings = { }), getRunPastTimeoutTitle: () => i18n.translate('controls.optionsList.editor.runPastTimeout', { - defaultMessage: 'Run past timeout', + defaultMessage: 'Ignore timeout for results', + }), + getRunPastTimeoutTooltip: () => + i18n.translate('controls.optionsList.editor.runPastTimeout.tooltip', { + defaultMessage: + 'Wait to display results until the list is complete. This setting is useful for large data sets, but the results might take longer to populate.', + }), + getHideExcludeTitle: () => + i18n.translate('controls.optionsList.editor.hideExclude', { + defaultMessage: 'Allow selections to be excluded', }), }, popover: { @@ -86,5 +99,17 @@ export const OptionsListStrings = { '{selectedOptions} selected {selectedOptions, plural, one {option} other {options}} {selectedOptions, plural, one {is} other {are}} ignored because {selectedOptions, plural, one {it is} other {they are}} no longer in the data.', values: { selectedOptions }, }), + getIncludeLabel: () => + i18n.translate('controls.optionsList.popover.includeLabel', { + defaultMessage: 'Include', + }), + getExcludeLabel: () => + i18n.translate('controls.optionsList.popover.excludeLabel', { + defaultMessage: 'Exclude', + }), + getIncludeExcludeLegend: () => + i18n.translate('controls.optionsList.popover.excludeOptionsLegend', { + defaultMessage: 'Include or exclude selections', + }), }, }; diff --git a/src/plugins/controls/public/options_list/embeddable/options_list_embeddable.tsx b/src/plugins/controls/public/options_list/embeddable/options_list_embeddable.tsx index 292e7cb6b0597..ffead8d9c20bc 100644 --- a/src/plugins/controls/public/options_list/embeddable/options_list_embeddable.tsx +++ b/src/plugins/controls/public/options_list/embeddable/options_list_embeddable.tsx @@ -134,6 +134,7 @@ export class OptionsListEmbeddable extends Embeddable isEqual(a.selectedOptions, b.selectedOptions))) + .pipe( + distinctUntilChanged( + (a, b) => isEqual(a.selectedOptions, b.selectedOptions) && a.exclude === b.exclude + ) + ) .subscribe(async ({ selectedOptions: newSelectedOptions }) => { const { actions: { @@ -364,6 +369,7 @@ export class OptionsListEmbeddable extends Embeddable { const { getState } = this.reduxEmbeddableTools; const { validSelections } = getState().componentState ?? {}; + const { exclude } = this.getInput(); if (!validSelections || isEmpty(validSelections)) { return []; @@ -379,6 +385,7 @@ export class OptionsListEmbeddable extends Embeddable) => { if (state.explicitInput.selectedOptions) state.explicitInput.selectedOptions = []; }, + setExclude: (state: WritableDraft, action: PayloadAction) => { + state.explicitInput.exclude = action.payload; + }, clearValidAndInvalidSelections: (state: WritableDraft) => { state.componentState.invalidSelections = []; state.componentState.validSelections = []; diff --git a/src/plugins/custom_integrations/common/language_integrations.ts b/src/plugins/custom_integrations/common/language_integrations.ts index 9ba914c02fd0d..8a24295096b40 100644 --- a/src/plugins/custom_integrations/common/language_integrations.ts +++ b/src/plugins/custom_integrations/common/language_integrations.ts @@ -37,9 +37,9 @@ export const languageIntegrations: LanguageIntegration[] = [ description: i18n.translate('customIntegrations.languageclients.JavascriptDescription', { defaultMessage: 'Index data to Elasticsearch with the JavaScript client.', }), - docUrlTemplate: `${ELASTICSEARCH_CLIENT_URL}/javascript-api/{branch}/introduction.html`, + docUrlTemplate: '', integrationsAppUrl: `/app/integrations/language_clients/javascript/overview`, - exportLanguageUiComponent: false, + exportLanguageUiComponent: true, }, { id: 'ruby', diff --git a/src/plugins/custom_integrations/public/components/fleet_integration/elasticsearch_js/elasticsearch_js_readme.tsx b/src/plugins/custom_integrations/public/components/fleet_integration/elasticsearch_js/elasticsearch_js_readme.tsx new file mode 100644 index 0000000000000..0202782efe436 --- /dev/null +++ b/src/plugins/custom_integrations/public/components/fleet_integration/elasticsearch_js/elasticsearch_js_readme.tsx @@ -0,0 +1,204 @@ +/* + * Copyright 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, { useState } from 'react'; + +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; +import cuid from 'cuid'; + +import { + EuiButton, + EuiCode, + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageSection, + EuiSpacer, + EuiText, + EuiTitle, + EuiPanel, + EuiImage, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import icon from '../../../assets/language_clients/nodejs.svg'; + +const CenterColumn = styled(EuiFlexItem)` + max-width: 740px; +`; + +const FixedHeader = styled.div` + width: 100%; + height: 196px; + border-bottom: 1px solid ${euiThemeVars.euiColorLightShade}; +`; + +const IconPanel = styled(EuiPanel)` + padding: ${(props) => props.theme.eui.euiSizeXL}; + width: ${(props) => + parseFloat(props.theme.eui.euiSize) * 6 + parseFloat(props.theme.eui.euiSizeXL) * 2}px; + svg, + img { + height: ${(props) => parseFloat(props.theme.eui.euiSize) * 6}px; + width: ${(props) => parseFloat(props.theme.eui.euiSize) * 6}px; + } + .euiFlexItem { + height: ${(props) => parseFloat(props.theme.eui.euiSize) * 6}px; + justify-content: center; + } +`; + +const TopFlexGroup = styled(EuiFlexGroup)` + max-width: 1150px; + margin-left: auto; + margin-right: auto; + padding: calc(${euiThemeVars.euiSizeXL} * 2) ${euiThemeVars.euiSizeM} 0 ${euiThemeVars.euiSizeM}; +`; + +export const ElasticsearchJsClientReadme = () => { + const [apiKey, setApiKey] = useState(null); + + return ( + <> + + + + + + + + + +

+ +

+
+
+
+
+ + + + + + + + + + } + /> + + + + +

+ +

+
+ + + + + {`# Grab the Elasticsearch JavaScript client from NPM and install it in your project \n`} + {`$ npm install @elastic/elasticsearch@`} + +
+ + + +

+ +

+
+ + + + + + + + + + setApiKey(cuid())} disabled={!!apiKey}> + Generate API key + + + + {apiKey && ( + + + {apiKey} + + + )} + +
+ + + +

+ +

+
+ + + index.js, + }} + /> + + + + + + {` +// Import the client +const { Client } = require('@elastic/elasticsearch'); + +// Instantiate the client with an API key +const client = new Client({ + auth: { apiKey: '${apiKey || 'YOUR_API_KEY'}' } +}) + + `} + +
+
+
+
+
+ + ); +}; diff --git a/src/plugins/custom_integrations/public/components/fleet_integration/sample/sample_client_readme.tsx b/src/plugins/custom_integrations/public/components/fleet_integration/sample/sample_client_readme.tsx index c2ca0d62da689..7b932ca9c99f7 100644 --- a/src/plugins/custom_integrations/public/components/fleet_integration/sample/sample_client_readme.tsx +++ b/src/plugins/custom_integrations/public/components/fleet_integration/sample/sample_client_readme.tsx @@ -81,7 +81,7 @@ export const SampleClientReadme = () => {

diff --git a/src/plugins/custom_integrations/public/plugin.tsx b/src/plugins/custom_integrations/public/plugin.tsx index 827d31ce3749d..e1e10f327075c 100755 --- a/src/plugins/custom_integrations/public/plugin.tsx +++ b/src/plugins/custom_integrations/public/plugin.tsx @@ -23,6 +23,7 @@ import { import { CustomIntegrationsServicesProvider } from './services'; import { servicesFactory } from './services/kibana'; import { SampleClientReadme } from './components/fleet_integration/sample/sample_client_readme'; +import { ElasticsearchJsClientReadme } from './components/fleet_integration/elasticsearch_js/elasticsearch_js_readme'; export class CustomIntegrationsPlugin implements Plugin @@ -46,7 +47,10 @@ export class CustomIntegrationsPlugin ): CustomIntegrationsStart { const services = servicesFactory({ coreStart, startPlugins }); - const languageClientsUiComponents = { sample: SampleClientReadme }; + const languageClientsUiComponents = { + sample: SampleClientReadme, + javascript: ElasticsearchJsClientReadme, + }; const ContextProvider: React.FC = ({ children }) => ( diff --git a/src/plugins/custom_integrations/server/plugin.test.ts b/src/plugins/custom_integrations/server/plugin.test.ts index 0bfc014ed5cdd..324522a383d83 100644 --- a/src/plugins/custom_integrations/server/plugin.test.ts +++ b/src/plugins/custom_integrations/server/plugin.test.ts @@ -37,8 +37,7 @@ describe('CustomIntegrationsPlugin', () => { description: 'Index data to Elasticsearch with the JavaScript client.', type: 'ui_link', shipper: 'language_clients', - uiInternalPath: - 'https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/branch/introduction.html', + uiInternalPath: '/app/integrations/language_clients/javascript/overview', isBeta: false, icons: [{ type: 'svg', src: undefined }], categories: ['elastic_stack', 'custom', 'language_client'], @@ -150,7 +149,7 @@ describe('CustomIntegrationsPlugin', () => { uiExternalLink: 'https://serverlessrepo.aws.amazon.com/applications/eu-central-1/267093732750/elastic-serverless-forwarder', isBeta: false, - icons: [{ type: 'svg' }], + icons: [{ type: 'svg', src: undefined }], categories: ['aws', 'custom'], }, ]); diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx index b6c3d2055d88c..7ad4b64324507 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx @@ -46,7 +46,7 @@ beforeEach(() => { application = applicationServiceMock.createStartContract(); }); -test('DashboardContainer initializes embeddables', async (done) => { +test('DashboardContainer initializes embeddables', (done) => { const initialInput = getSampleDashboardInput({ panels: { '123': getSampleDashboardPanel({ @@ -96,7 +96,7 @@ test('DashboardContainer.addNewEmbeddable', async () => { expect(embeddableInContainer.id).toBe(embeddable.id); }); -test('DashboardContainer.replacePanel', async (done) => { +test('DashboardContainer.replacePanel', (done) => { const ID = '123'; const initialInput = getSampleDashboardInput({ panels: { @@ -139,7 +139,7 @@ test('DashboardContainer.replacePanel', async (done) => { }); }); -test('Container view mode change propagates to existing children', async (done) => { +test('Container view mode change propagates to existing children', async () => { const initialInput = getSampleDashboardInput({ panels: { '123': getSampleDashboardPanel({ @@ -154,7 +154,6 @@ test('Container view mode change propagates to existing children', async (done) expect(embeddable.getInput().viewMode).toBe(ViewMode.VIEW); container.updateInput({ viewMode: ViewMode.EDIT }); expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT); - done(); }); test('Container view mode change propagates to new children', async () => { diff --git a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx index 41e8b900d360f..6972a521026b4 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx @@ -139,7 +139,7 @@ test.skip('DashboardGrid renders expanded panel', () => { }); // unhandled promise rejection: https://github.com/elastic/kibana/issues/112699 -test.skip('DashboardGrid unmount unsubscribes', async (done) => { +test.skip('DashboardGrid unmount unsubscribes', (done) => { const { props } = prepare(); const component = mountWithIntl( diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx index 27c86a8ff6c09..a7bad078b56eb 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx @@ -160,7 +160,7 @@ test.skip('renders exit full screen button when in full screen mode and empty sc }); // unhandled promise rejection: https://github.com/elastic/kibana/issues/112699 -test.skip('DashboardViewport unmount unsubscribes', async (done) => { +test.skip('DashboardViewport unmount unsubscribes', (done) => { const { props } = getProps(); const component = mount( diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts index 850c6f575904c..6095598ae3788 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts @@ -13,6 +13,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; import { ViewMode } from '@kbn/embeddable-plugin/public'; +import type { DataView } from '@kbn/data-plugin/common'; import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { @@ -225,7 +226,14 @@ export const useDashboardAppState = ({ dashboardContainer.controlGroup?.setRelevantDataViewId(newDataViewIds[0]); } // fetch all data views. These should be cached locally at this time so we will not need to query ES. - const allDataViews = await Promise.all(newDataViewIds.map((id) => dataViews.get(id))); + const responses = await Promise.allSettled(newDataViewIds.map((id) => dataViews.get(id))); + // Keep only fullfilled ones as each panel will handle the rejected ones already on their own + const allDataViews = responses + .filter( + (response): response is PromiseFulfilledResult => + response.status === 'fulfilled' + ) + .map(({ value }) => value); dashboardContainer.setAllDataViews(allDataViews); setDashboardAppState((s) => ({ ...s, dataViews: allDataViews })); }, diff --git a/src/plugins/dashboard/public/application/lib/help_menu_util.ts b/src/plugins/dashboard/public/application/lib/help_menu_util.ts index 9407fa31f545a..d93b2593386ba 100644 --- a/src/plugins/dashboard/public/application/lib/help_menu_util.ts +++ b/src/plugins/dashboard/public/application/lib/help_menu_util.ts @@ -12,9 +12,8 @@ import { pluginServices } from '../../services/plugin_services'; export function addHelpMenuToAppChrome() { const { chrome: { setHelpExtension }, - documentationLinks: { kibanaGuideDocLink }, + documentationLinks: { dashboardDocLink }, } = pluginServices.getServices(); - setHelpExtension({ appName: i18n.translate('dashboard.helpMenu.appName', { defaultMessage: 'Dashboards', @@ -22,7 +21,7 @@ export function addHelpMenuToAppChrome() { links: [ { linkType: 'documentation', - href: `${kibanaGuideDocLink}`, + href: `${dashboardDocLink}`, }, ], }); diff --git a/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts b/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts index 3fab07396b4ff..dfdd74bfe4184 100644 --- a/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts +++ b/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts @@ -18,5 +18,6 @@ export const documentationLinksServiceFactory: DocumentationLinksServiceFactory return { indexPatternsDocLink: corePluginMock.docLinks.links.indexPatterns.introduction, kibanaGuideDocLink: corePluginMock.docLinks.links.kibana.guide, + dashboardDocLink: corePluginMock.docLinks.links.dashboard.guide, }; }; diff --git a/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts b/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts index fe00d376675f6..eb65f639d57fe 100644 --- a/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts +++ b/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts @@ -21,14 +21,16 @@ export const documentationLinksServiceFactory: DocumentationLinksServiceFactory const { docLinks: { links: { - kibana: { guide }, + kibana, indexPatterns: { introduction }, + dashboard, }, }, } = coreStart; return { indexPatternsDocLink: introduction, - kibanaGuideDocLink: guide, + kibanaGuideDocLink: kibana.guide, + dashboardDocLink: dashboard.guide, }; }; diff --git a/src/plugins/dashboard/public/services/documentation_links/types.ts b/src/plugins/dashboard/public/services/documentation_links/types.ts index ee7e520471651..d47fbee6ed772 100644 --- a/src/plugins/dashboard/public/services/documentation_links/types.ts +++ b/src/plugins/dashboard/public/services/documentation_links/types.ts @@ -11,4 +11,5 @@ import { CoreStart } from '@kbn/core/public'; export interface DashboardDocumentationLinksService { indexPatternsDocLink: CoreStart['docLinks']['links']['indexPatterns']['introduction']; kibanaGuideDocLink: CoreStart['docLinks']['links']['kibana']['guide']; + dashboardDocLink: CoreStart['docLinks']['links']['dashboard']['guide']; } diff --git a/src/plugins/data/public/query/filter_manager/lib/generate_mapping_chain.test.ts b/src/plugins/data/public/query/filter_manager/lib/generate_mapping_chain.test.ts index 7c86581b42a6b..e0cd902836df6 100644 --- a/src/plugins/data/public/query/filter_manager/lib/generate_mapping_chain.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/generate_mapping_chain.test.ts @@ -86,7 +86,7 @@ describe('filter manager utilities', () => { expect(result).toEqual({ key: 'test', value: 'example' }); }); - test('should throw an error if no functions match', async (done) => { + test('should throw an error if no functions match', async () => { const filter = buildEmptyFilter(true); mapping.throws(filter); @@ -98,7 +98,6 @@ describe('filter manager utilities', () => { } catch (err) { expect(err).toBeInstanceOf(Error); expect(err.message).toBe('No mappings have been found for filter.'); - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/map_filter.test.ts b/src/plugins/data/public/query/filter_manager/lib/map_filter.test.ts index ff9c6d47660fd..e0bc31787df0f 100644 --- a/src/plugins/data/public/query/filter_manager/lib/map_filter.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/map_filter.test.ts @@ -54,7 +54,7 @@ describe('filter manager utilities', () => { expect(after.meta).toHaveProperty('negate', false); }); - test('should finish with a catch', async (done) => { + test('should finish with a catch', async () => { const before: any = { meta: { index: 'logstash-*' } }; try { @@ -62,8 +62,6 @@ describe('filter manager utilities', () => { } catch (e) { expect(e).toBeInstanceOf(Error); expect(e.message).toBe('No mappings have been found for filter.'); - - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_exists.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_exists.test.ts index 0e642b3f99dcc..b46f5b4c488e3 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_exists.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_exists.test.ts @@ -29,14 +29,13 @@ describe('filter manager utilities', () => { expect(result).toHaveProperty('value', 'exists'); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', async () => { const filter = buildEmptyFilter(true); try { mapQueryString(filter); } catch (e) { expect(e).toBe(filter); - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrase.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrase.test.ts index 88e819bb7f9a7..93d5547f1b9e6 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrase.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrase.test.ts @@ -23,7 +23,7 @@ describe('filter manager utilities', () => { expect(result).toHaveProperty('key', '_type'); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', async () => { const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } }, @@ -33,7 +33,6 @@ describe('filter manager utilities', () => { mapPhrase(filter); } catch (e) { expect(e).toBe(filter); - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.test.ts index 4a219e23aff09..6c69f0ff948d9 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.test.ts @@ -29,7 +29,7 @@ describe('filter manager utilities', () => { expect(result).toHaveProperty('value', ['hello', 1, 'world']); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', (done) => { const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } }, diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_query_string.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_query_string.test.ts index f54cea3164919..df5347c33e6a0 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_query_string.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_query_string.test.ts @@ -19,14 +19,13 @@ describe('filter manager utilities', () => { expect(result).toHaveProperty('value', 'foo:bar'); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', async () => { const filter = buildEmptyFilter(true); try { mapQueryString(filter as Filter); } catch (e) { expect(e).toBe(filter); - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_range.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_range.test.ts index 065e3da189999..82c701a510dfa 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_range.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_range.test.ts @@ -22,7 +22,7 @@ describe('filter manager utilities', () => { expect(result).toHaveProperty('value', { gt: 1024, lt: 2048 }); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', async () => { const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } }, @@ -32,8 +32,6 @@ describe('filter manager utilities', () => { mapRange(filter); } catch (e) { expect(e).toBe(filter); - - done(); } }); }); diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.test.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.test.ts index 9065ccfa17856..67dd343dd33c4 100644 --- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.test.ts @@ -109,7 +109,7 @@ describe('mapSpatialFilter()', () => { expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER); }); - test('should return undefined for none matching', async (done) => { + test('should return undefined for none matching', async () => { const filter = { meta: { key: 'location', @@ -124,8 +124,6 @@ describe('mapSpatialFilter()', () => { mapSpatialFilter(filter); } catch (e) { expect(e).toBe(filter); - - done(); } }); }); diff --git a/src/plugins/data/public/query/timefilter/lib/auto_refresh_loop.test.ts b/src/plugins/data/public/query/timefilter/lib/auto_refresh_loop.test.ts index 3c8b316c3b878..fc30a120c445f 100644 --- a/src/plugins/data/public/query/timefilter/lib/auto_refresh_loop.test.ts +++ b/src/plugins/data/public/query/timefilter/lib/auto_refresh_loop.test.ts @@ -8,7 +8,7 @@ import { createAutoRefreshLoop, AutoRefreshDoneFn } from './auto_refresh_loop'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); test('triggers refresh with interval', () => { const { loop$, start, stop } = createAutoRefreshLoop(); diff --git a/src/plugins/data/public/query/timefilter/timefilter.test.ts b/src/plugins/data/public/query/timefilter/timefilter.test.ts index 0152076c7b8a6..7ba6f07835f7b 100644 --- a/src/plugins/data/public/query/timefilter/timefilter.test.ts +++ b/src/plugins/data/public/query/timefilter/timefilter.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); import sinon from 'sinon'; import moment from 'moment'; diff --git a/src/plugins/data/public/search/search_interceptor/search_abort_controller.test.ts b/src/plugins/data/public/search/search_interceptor/search_abort_controller.test.ts index 5d9d8a9903325..82d917216f306 100644 --- a/src/plugins/data/public/search/search_interceptor/search_abort_controller.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_abort_controller.test.ts @@ -10,7 +10,7 @@ import { SearchAbortController } from './search_abort_controller'; const timeTravel = (msToRun = 0) => { jest.advanceTimersByTime(msToRun); - return new Promise((resolve) => setImmediate(resolve)); + return new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); }; describe('search abort controller', () => { @@ -75,7 +75,7 @@ describe('search abort controller', () => { describe('timeout abort', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 35bbecfdb5c4d..73ce6672064aa 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -41,8 +41,10 @@ let mockCoreSetup: MockedKeys; let bfetchSetup: jest.Mocked; let fetchMock: jest.Mock; -const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); -jest.useFakeTimers(); +const flushPromises = () => + new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); + +jest.useFakeTimers('legacy'); const timeTravel = async (msToRun = 0) => { await flushPromises(); @@ -1531,7 +1533,7 @@ describe('SearchInterceptor', () => { await flushPromises(); }); - test('Immediately aborts if passed an aborted abort signal', async (done) => { + test('Immediately aborts if passed an aborted abort signal', async () => { const abort = new AbortController(); const mockRequest: IEsSearchRequest = { params: {}, @@ -1542,7 +1544,6 @@ describe('SearchInterceptor', () => { error.mockImplementation((e) => { expect(e).toBeInstanceOf(AbortError); expect(fetchMock).not.toBeCalled(); - done(); }); response.subscribe({ error }); diff --git a/src/plugins/data/public/search/session/session_helpers.test.ts b/src/plugins/data/public/search/session/session_helpers.test.ts index bc092a4f6ac3f..8d33d58b55acc 100644 --- a/src/plugins/data/public/search/session/session_helpers.test.ts +++ b/src/plugins/data/public/search/session/session_helpers.test.ts @@ -65,7 +65,7 @@ beforeEach(() => { describe('waitUntilNextSessionCompletes$', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { jest.useRealTimers(); diff --git a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx index 9f29e2866fb61..1174142db213f 100644 --- a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx +++ b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx @@ -226,7 +226,7 @@ describe('Completed inactivity', () => { describe('tour steps', () => { describe('loading state', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx index ac554af701d04..be398ba7294fc 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx @@ -152,7 +152,7 @@ describe('Background Search Session Management Table', () => { // FLAKY: https://github.com/elastic/kibana/issues/88928 describe.skip('fetching sessions data', () => { test('re-fetches data', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); sessionsClient.find = jest.fn(); mockConfig = { ...mockConfig, diff --git a/src/plugins/data/server/lib/get_request_aborted_signal.test.ts b/src/plugins/data/server/lib/get_request_aborted_signal.test.ts index 3a94d020de4da..eb0c590c9c7bc 100644 --- a/src/plugins/data/server/lib/get_request_aborted_signal.test.ts +++ b/src/plugins/data/server/lib/get_request_aborted_signal.test.ts @@ -10,7 +10,7 @@ import { Subject } from 'rxjs'; import { getRequestAbortedSignal } from './get_request_aborted_signal'; describe('abortableRequestHandler', () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); it('should call abort if disconnected', () => { const abortedSubject = new Subject(); diff --git a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts index d8413703808c7..15a6a4df7eed8 100644 --- a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts @@ -58,7 +58,7 @@ describe('ES search strategy', () => { expect(typeof esSearch.search).toBe('function'); }); - it('calls the API caller with the params with defaults', async (done) => { + it('calls the API caller with the params with defaults', async () => { const params = { index: 'logstash-*' }; await esSearchStrategyProvider(mockConfig$, mockLogger) @@ -70,11 +70,10 @@ describe('ES search strategy', () => { ignore_unavailable: true, track_total_hits: true, }); - done(); }); }); - it('calls the API caller with overridden defaults', async (done) => { + it('calls the API caller with overridden defaults', async () => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; await esSearchStrategyProvider(mockConfig$, mockLogger) @@ -85,11 +84,10 @@ describe('ES search strategy', () => { ...params, track_total_hits: true, }); - done(); }); }); - it('has all response parameters', async (done) => + it('has all response parameters', async () => await esSearchStrategyProvider(mockConfig$, mockLogger) .search( { @@ -103,7 +101,6 @@ describe('ES search strategy', () => { expect(data.isPartial).toBe(false); expect(data).toHaveProperty('loaded'); expect(data).toHaveProperty('rawResponse'); - done(); })); it('calls the client with transport options', async () => { @@ -137,7 +134,7 @@ describe('ES search strategy', () => { expect(esClient.search.mock.calls[0][1]).toEqual({ signal: expect.any(AbortSignal) }); }); - it('throws normalized error if ResponseError is thrown', async (done) => { + it('throws normalized error if ResponseError is thrown', async () => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; const errResponse = new errors.ResponseError({ body: indexNotFoundException, @@ -157,11 +154,10 @@ describe('ES search strategy', () => { expect(e.statusCode).toBe(404); expect(e.message).toBe(errResponse.message); expect(e.errBody).toBe(indexNotFoundException); - done(); } }); - it('throws normalized error if ElasticsearchClientError is thrown', async (done) => { + it('throws normalized error if ElasticsearchClientError is thrown', async () => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; const errResponse = new errors.ElasticsearchClientError('This is a general ESClient error'); @@ -175,11 +171,10 @@ describe('ES search strategy', () => { expect(e.statusCode).toBe(500); expect(e.message).toBe(errResponse.message); expect(e.errBody).toBe(undefined); - done(); } }); - it('throws normalized error if ESClient throws unknown error', async (done) => { + it('throws normalized error if ESClient throws unknown error', async () => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; const errResponse = new Error('ESClient error'); @@ -193,11 +188,10 @@ describe('ES search strategy', () => { expect(e.statusCode).toBe(500); expect(e.message).toBe(errResponse.message); expect(e.errBody).toBe(undefined); - done(); } }); - it('throws KbnServerError for unknown index type', async (done) => { + it('throws KbnServerError for unknown index type', async () => { const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; try { @@ -210,7 +204,6 @@ describe('ES search strategy', () => { expect(e.message).toBe('Unsupported index pattern type banana'); expect(e.statusCode).toBe(400); expect(e.errBody).toBe(undefined); - done(); } }); }); diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index a1ac225ba4b38..8d666590b3d30 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -346,8 +346,18 @@ export function getUiSettings( "to": "now" }`, type: 'json', - description: i18n.translate('data.advancedSettings.timepicker.timeDefaultsText', { - defaultMessage: 'The timefilter selection to use when Kibana is started without one', + description: i18n.translate('data.advancedSettings.timepicker.timeDefaultsDescription', { + defaultMessage: + 'The timefilter selection to use when Kibana is started without one. Must be an object containing "from" and "to" (see {acceptedFormatsLink}).', + values: { + acceptedFormatsLink: + `` + + i18n.translate('data.advancedSettings.timepicker.quickRanges.acceptedFormatsLinkText', { + defaultMessage: 'accepted formats', + }) + + '', + }, }), requiresPageReload: true, schema: schema.object({ diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx index 50dce25679252..825402fd00a24 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor.test.tsx @@ -65,7 +65,7 @@ describe('', () => { }; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts index 51cd024f0b53e..094c38e0eb715 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_content.test.ts @@ -18,7 +18,7 @@ describe('', () => { const { httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts index 8659e12909763..66cf2bab43d3d 100644 --- a/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts +++ b/src/plugins/data_view_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts @@ -27,7 +27,7 @@ describe('Field editor Preview panel', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/discover/public/application/main/utils/get_fetch_observeable.test.ts b/src/plugins/discover/public/application/main/utils/get_fetch_observeable.test.ts index e39642ac2bce2..0d0f1f0802bff 100644 --- a/src/plugins/discover/public/application/main/utils/get_fetch_observeable.test.ts +++ b/src/plugins/discover/public/application/main/utils/get_fetch_observeable.test.ts @@ -51,7 +51,7 @@ describe('getFetchObservable', () => { jest.useRealTimers(); }); - test('refetch$.next should trigger fetch$.next', async (done) => { + test('refetch$.next should trigger fetch$.next', (done) => { const searchSessionManagerMock = createSearchSessionMock(); const main$ = new BehaviorSubject({ fetchStatus: FetchStatus.UNINITIALIZED }); @@ -75,7 +75,7 @@ describe('getFetchObservable', () => { test( 'getAutoRefreshFetch$ should trigger fetch$.next', fakeSchedulers((advance) => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const searchSessionManagerMock = createSearchSessionMock(); const autoRefreshFetch$ = new Subject(); diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx index de0bcf3f8654c..079a31089d707 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx @@ -43,7 +43,7 @@ class OutputTestEmbeddable extends Embeddable { reload() {} } -test('Embeddable calls input subscribers when changed', async (done) => { +test('Embeddable calls input subscribers when changed', (done) => { const hello = new ContactCardEmbeddable( { id: '123', firstName: 'Brienne', lastName: 'Tarth' }, { execAction: (() => null) as any } diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx index 8f096020ae60e..d482354ca509e 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx @@ -57,7 +57,7 @@ setup.registerEmbeddableFactory(embeddableReactFactory.type, embeddableReactFact const start = doStart(); const getEmbeddableFactory = start.getEmbeddableFactory; -test('HelloWorldContainer initializes embeddables', async (done) => { +test('HelloWorldContainer initializes embeddables', (done) => { const container = new HelloWorldContainer( { id: '123', diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts index 983f9ceedf369..58f15c326be77 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts @@ -53,7 +53,7 @@ beforeEach(async () => { } }); -test('Updates the embeddable title when given', async (done) => { +test('Updates the embeddable title when given', async () => { const getUserData = () => Promise.resolve({ title: 'What is up?' }); const customizePanelAction = new CustomizePanelTitleAction(getUserData); expect(embeddable.getInput().title).toBeUndefined(); @@ -66,11 +66,10 @@ test('Updates the embeddable title when given', async (done) => { // Recreating the container should preserve the custom title. const containerClone = createHelloWorldContainer(container.getInput()); // Need to wait for the container to tell us the embeddable has been loaded. - const subscription = containerClone.getOutput$().subscribe(() => { + const subscription = await containerClone.getOutput$().subscribe(() => { if (containerClone.getOutput().embeddableLoaded[embeddable.id]) { expect(embeddable.getInput().title).toBe('What is up?'); subscription.unsubscribe(); - done(); } }); }); diff --git a/src/plugins/embeddable/public/tests/container.test.ts b/src/plugins/embeddable/public/tests/container.test.ts index 8b487d9f02f78..c6088e95069cb 100644 --- a/src/plugins/embeddable/public/tests/container.test.ts +++ b/src/plugins/embeddable/public/tests/container.test.ts @@ -128,7 +128,7 @@ describe('container initialization', () => { expect(embeddable.id).toBe('123'); }; - it('initializes embeddables', async (done) => { + it('initializes embeddables', async () => { const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels, @@ -137,10 +137,9 @@ describe('container initialization', () => { expectEmbeddableLoaded(container, '123'); expectEmbeddableLoaded(container, '456'); expectEmbeddableLoaded(container, '789'); - done(); }); - it('initializes embeddables once and only once with multiple input updates', async (done) => { + it('initializes embeddables once and only once with multiple input updates', async () => { const { container, contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels, @@ -148,10 +147,9 @@ describe('container initialization', () => { container.updateInput({ lastReloadRequestTime: 1 }); container.updateInput({ lastReloadRequestTime: 2 }); expect(contactCardCreateSpy).toHaveBeenCalledTimes(4); - done(); }); - it('initializes embeddables in order', async (done) => { + it('initializes embeddables in order', async () => { const childIdInitializeOrder = ['456', '123', '789']; const { contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( { @@ -170,10 +168,9 @@ describe('container initialization', () => { expect.anything() // parent passed into create method ); } - done(); }); - it('initializes embeddables in order with partial order arg', async (done) => { + it('initializes embeddables in order with partial order arg', async () => { const childIdInitializeOrder = ['789', 'idontexist']; const { contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( { @@ -193,10 +190,9 @@ describe('container initialization', () => { expect.anything() // parent passed into create method ); } - done(); }); - it('initializes embeddables in order, awaiting each', async (done) => { + it('initializes embeddables in order, awaiting each', async () => { const childIdInitializeOrder = ['456', '123', '789']; const { container, contactCardCreateSpy } = await createHelloWorldContainerAndEmbeddable( { @@ -220,7 +216,6 @@ describe('container initialization', () => { ); expect(untilEmbeddableLoadedMock).toHaveBeenCalledWith(orderedId); } - done(); }); }); @@ -244,7 +239,7 @@ test('Container.addNewEmbeddable', async () => { expect(embeddableInContainer.id).toBe(embeddable.id); }); -test('Container.removeEmbeddable removes and cleans up', async (done) => { +test('Container.removeEmbeddable removes and cleans up', async () => { const { start, testPanel } = await createHelloWorldContainerAndEmbeddable(); const container = new HelloWorldContainer( @@ -288,12 +283,10 @@ test('Container.removeEmbeddable removes and cleans up', async (done) => { expect(container.getInput().panels[embeddable.id]).toBeUndefined(); if (isErrorEmbeddable(embeddable)) { expect(false).toBe(true); - done(); } expect(() => embeddable.updateInput({ nameTitle: 'Sir' })).toThrowError(); expect(container.getOutput().embeddableLoaded[embeddable.id]).toBeUndefined(); - done(); }); container.removeEmbeddable(embeddable.id); @@ -403,7 +396,7 @@ test('Container view mode change propagates to children', async () => { expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT); }); -test(`Container updates its state when a child's input is updated`, async (done) => { +test(`Container updates its state when a child's input is updated`, async () => { const { container, embeddable, start, coreStart, uiActions } = await createHelloWorldContainerAndEmbeddable( { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, @@ -450,7 +443,6 @@ test(`Container updates its state when a child's input is updated`, async (done) childClone.getInput().nameTitle === 'Dr.' ) { cloneSubscription.unsubscribe(); - done(); } }); } @@ -487,7 +479,7 @@ test(`Derived container state passed to children`, async () => { subscription.unsubscribe(); }); -test(`Can subscribe to children embeddable updates`, async (done) => { +test(`Can subscribe to children embeddable updates`, async () => { const { embeddable } = await createHelloWorldContainerAndEmbeddable( { id: 'hello container', @@ -504,13 +496,12 @@ test(`Can subscribe to children embeddable updates`, async (done) => { const subscription = embeddable.getInput$().subscribe((input: ContactCardEmbeddableInput) => { if (input.nameTitle === 'Dr.') { subscription.unsubscribe(); - done(); } }); embeddable.updateInput({ nameTitle: 'Dr.' }); }); -test('Test nested reactions', async (done) => { +test('Test nested reactions', async () => { const { container, embeddable } = await createHelloWorldContainerAndEmbeddable( { id: 'hello', panels: {}, viewMode: ViewMode.VIEW }, { @@ -533,7 +524,6 @@ test('Test nested reactions', async (done) => { ) { containerSubscription.unsubscribe(); embeddableSubscription.unsubscribe(); - done(); } }); @@ -578,7 +568,7 @@ test('Explicit embeddable input mapped to undefined will default to inherited', ]); }); -test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async (done) => { +test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async () => { const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels: {} }); const embeddable = await container.addNewEmbeddable< @@ -601,7 +591,6 @@ test('Explicit embeddable input mapped to undefined with no inherited value will .subscribe(() => { if (embeddable.getInput().filters === undefined) { subscription.unsubscribe(); - done(); } }); @@ -666,7 +655,7 @@ test('Panel added to input state', async () => { expect(container.getOutput().embeddableLoaded[embeddable2.id]).toBe(true); }); -test('Container changes made directly after adding a new embeddable are propagated', async (done) => { +test('Container changes made directly after adding a new embeddable are propagated', async () => { const coreSetup = coreMock.createSetup(); const coreStart = coreMock.createStart(); const { setup, doStart, uiActions } = testPlugin(coreSetup, coreStart); @@ -710,7 +699,6 @@ test('Container changes made directly after adding a new embeddable are propagat const embeddable = container.getChild(embeddableId); if (embeddable.getInput().viewMode === ViewMode.VIEW) { subscription.unsubscribe(); - done(); } } } @@ -724,7 +712,7 @@ test('Container changes made directly after adding a new embeddable are propagat container.updateInput({ viewMode: ViewMode.VIEW }); }); -test('container stores ErrorEmbeddables when a factory for a child cannot be found (so the panel can be removed)', async (done) => { +test('container stores ErrorEmbeddables when a factory for a child cannot be found (so the panel can be removed)', async () => { const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels: { @@ -740,12 +728,11 @@ test('container stores ErrorEmbeddables when a factory for a child cannot be fou if (container.getOutput().embeddableLoaded['123']) { const child = container.getChild('123'); expect(child.type).toBe(ERROR_EMBEDDABLE_TYPE); - done(); } }); }); -test('container stores ErrorEmbeddables when a saved object cannot be found', async (done) => { +test('container stores ErrorEmbeddables when a saved object cannot be found', async () => { const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels: { @@ -761,12 +748,11 @@ test('container stores ErrorEmbeddables when a saved object cannot be found', as if (container.getOutput().embeddableLoaded['123']) { const child = container.getChild('123'); expect(child.type).toBe(ERROR_EMBEDDABLE_TYPE); - done(); } }); }); -test('ErrorEmbeddables get updated when parent does', async (done) => { +test('ErrorEmbeddables get updated when parent does', async () => { const { container } = await createHelloWorldContainerAndEmbeddable({ id: 'hello', panels: { @@ -787,7 +773,6 @@ test('ErrorEmbeddables get updated when parent does', async (done) => { container.updateInput({ viewMode: ViewMode.VIEW }); expect(embeddable.getInput().viewMode).toBe(ViewMode.VIEW); - done(); } }); }); @@ -831,7 +816,7 @@ test('untilEmbeddableLoaded() throws an error if there is no such child panel in expect((error as Error).message).toMatchInlineSnapshot(`"Panel not found"`); }); -test('untilEmbeddableLoaded() resolves if child is loaded in the container', async (done) => { +test('untilEmbeddableLoaded() resolves if child is loaded in the container', async () => { const { setup, doStart, coreStart, uiActions } = testPlugin( coreMock.createSetup(), coreMock.createStart() @@ -866,10 +851,9 @@ test('untilEmbeddableLoaded() resolves if child is loaded in the container', asy const child = await container.untilEmbeddableLoaded('123'); expect(child).toBeDefined(); expect(child.type).toBe(HELLO_WORLD_EMBEDDABLE); - done(); }); -test('untilEmbeddableLoaded resolves with undefined if child is subsequently removed', async (done) => { +test('untilEmbeddableLoaded resolves with undefined if child is subsequently removed', async () => { const { doStart, setup, coreStart, uiActions } = testPlugin( coreMock.createSetup(), coreMock.createStart() @@ -907,13 +891,12 @@ test('untilEmbeddableLoaded resolves with undefined if child is subsequently rem container.untilEmbeddableLoaded('123').then((embed) => { expect(embed).toBeUndefined(); - done(); }); container.updateInput({ panels: {} }); }); -test('adding a panel then subsequently removing it before its loaded removes the panel', async (done) => { +test('adding a panel then subsequently removing it before its loaded removes the panel', (done) => { const { doStart, coreStart, uiActions, setup } = testPlugin( coreMock.createSetup(), coreMock.createStart() diff --git a/src/plugins/embeddable/public/tests/explicit_input.test.ts b/src/plugins/embeddable/public/tests/explicit_input.test.ts index d9a7b72ada15a..4ed4c12a80390 100644 --- a/src/plugins/embeddable/public/tests/explicit_input.test.ts +++ b/src/plugins/embeddable/public/tests/explicit_input.test.ts @@ -68,7 +68,7 @@ test('Explicit embeddable input mapped to undefined will default to inherited', ]); }); -test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async (done) => { +test('Explicit embeddable input mapped to undefined with no inherited value will get passed to embeddable', async () => { const testPanel = createEmbeddablePanelMock({ getActions: uiActions.getTriggerCompatibleActions, getEmbeddableFactory: start.getEmbeddableFactory, @@ -95,13 +95,12 @@ test('Explicit embeddable input mapped to undefined with no inherited value will expect(container.getInputForChild(embeddable.id).filters).toEqual([]); - const subscription = embeddable + const subscription = await embeddable .getInput$() .pipe(skip(1)) .subscribe(() => { if (embeddable.getInput().filters === undefined) { subscription.unsubscribe(); - done(); } }); diff --git a/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx b/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx index db694a29b793e..b75b645846eed 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx +++ b/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx @@ -49,7 +49,7 @@ const errorWithBodyResponse = { body: errorValue }; export const createUseRequestHelpers = (): UseRequestHelpers => { // The behavior we're testing involves state changes over time, so we need finer control over // timing. - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const flushPromiseJobQueue = async () => { // See https://stackoverflow.com/questions/52177631/jest-timer-and-promise-dont-work-well-settimeout-and-async-function diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.test.tsx index 8e9bdd35ffb7e..7a2d61c55d6c4 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.test.tsx @@ -18,7 +18,7 @@ import { UseArray } from './use_array'; describe('', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx index 36fd16209f5d4..6ea28fc601869 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx @@ -19,7 +19,7 @@ import { UseField } from './use_field'; describe('', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_multi_fields.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_multi_fields.test.tsx index 94c36613c44ba..09b0c898fc0dc 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_multi_fields.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_multi_fields.test.tsx @@ -15,7 +15,7 @@ import { UseMultiFields } from './use_multi_fields'; describe('', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.test.tsx index 71aafa6376884..4a3b5c99b978c 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.test.tsx @@ -17,7 +17,7 @@ import { FieldHook, FieldValidateResponse, VALIDATION_TYPES, FieldConfig } from describe('useField() hook', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.test.tsx index 9f57432b5d6a1..740dbf5ee5e75 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.test.tsx @@ -40,7 +40,7 @@ const onFormHook = (_form: FormHook) => { describe('useForm() hook', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/expressions/common/execution/execution.abortion.test.ts b/src/plugins/expressions/common/execution/execution.abortion.test.ts index 1664dd86870a8..71dca4f60c721 100644 --- a/src/plugins/expressions/common/execution/execution.abortion.test.ts +++ b/src/plugins/expressions/common/execution/execution.abortion.test.ts @@ -13,7 +13,7 @@ import { parseExpression } from '../ast'; import { createUnitTestExecutor } from '../test_helpers'; import { ExpressionFunctionDefinition } from '../expression_functions'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); beforeEach(() => { jest.clearAllTimers(); @@ -82,7 +82,7 @@ describe('Execution abortion tests', () => { expect(result).toBe(null); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); test('nested expressions are aborted when parent aborted', async () => { @@ -151,6 +151,6 @@ describe('Execution abortion tests', () => { expect(aborted).toHaveBeenCalledTimes(1); expect(completed).toHaveBeenCalledTimes(0); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); }); diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index 2d452b0a640ad..3575552401914 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -387,7 +387,7 @@ describe('Execution', () => { }); test('result is undefined until execution completes', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const execution = createExecution('sleep 10'); expect(execution.state.get().result).toBe(undefined); execution.start(null).subscribe(jest.fn()); @@ -561,7 +561,7 @@ describe('Execution', () => { }); test('execution state is "pending" while execution is in progress', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const execution = createExecution('sleep 20'); execution.start(null); jest.advanceTimersByTime(5); diff --git a/src/plugins/guided_onboarding/kibana.json b/src/plugins/guided_onboarding/kibana.json index 22a54e8dd3278..a7c1c3d217c1b 100755 --- a/src/plugins/guided_onboarding/kibana.json +++ b/src/plugins/guided_onboarding/kibana.json @@ -10,5 +10,5 @@ "server": true, "ui": true, "requiredBundles": ["kibanaReact"], - "optionalPlugins": [] + "optionalPlugins": ["cloud"] } diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.styles.ts b/src/plugins/guided_onboarding/public/components/guide_panel.styles.ts index 1ba565c9caee0..7e7f47670edf2 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.styles.ts +++ b/src/plugins/guided_onboarding/public/components/guide_panel.styles.ts @@ -40,8 +40,12 @@ export const getGuidePanelStyles = (euiTheme: EuiThemeComputed) => ({ `, flyoutFooter: css` border-radius: 0 0 6px 6px; - background: ${euiTheme.colors.ghost}; + background: transparent; padding: 24px 30px; `, + flyoutFooterLink: css` + color: ${euiTheme.colors.darkShade}; + font-weight: 400; + `, }, }); diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.tsx index ed021bc39c0ec..def898cae8a6b 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.tsx @@ -27,7 +27,6 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; import { ApplicationStart } from '@kbn/core/public'; import type { GuideState, GuideStep as GuideStepStatus } from '@kbn/guided-onboarding'; @@ -290,57 +289,59 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { - - - - {i18n.translate('guidedOnboarding.dropdownPanel.footer.exitGuideButtonLabel', { - defaultMessage: 'Quit setup guide', + + + + {i18n.translate('guidedOnboarding.dropdownPanel.footer.support', { + defaultMessage: 'Need help?', })} - - - - - {i18n.translate('guidedOnboarding.dropdownPanel.footer.feedbackLabel', { - defaultMessage: 'feedback', - })} - - ), - }} - /> + + + | - - - - - {i18n.translate( - 'guidedOnboarding.dropdownPanel.footer.helpTextDescription', - { - defaultMessage: 'here to help', - } - )} - - ), - }} - /> + + + {i18n.translate('guidedOnboarding.dropdownPanel.footer.feedback', { + defaultMessage: 'Give feedback', + })} + + + + + | + + + {i18n.translate('guidedOnboarding.dropdownPanel.footer.exitGuideButtonLabel', { + defaultMessage: 'Quit guide', + })} + + diff --git a/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts b/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts index 76ee412dbd382..5862d0d132735 100644 --- a/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts @@ -15,12 +15,12 @@ export const observabilityConfig: GuideConfig = { defaultMessage: 'Observe my Kubernetes infrastructure', }), description: i18n.translate('guidedOnboarding.observabilityGuide.description', { - defaultMessage: `We'll help you quickly gain visibility into your Kubernetes environment using Elastic's out-of-the-box integration. Gain deep insights from your logs, metrics, and traces, and proactively detect issues and take action to resolve issues.`, + defaultMessage: `We'll help you quickly get visibility into your Kubernetes environment with our Elastic integration. Gain deep insights from your logs, metrics, and traces to proactively detect issues and take action to resolve them.`, }), guideName: 'Kubernetes', docs: { text: i18n.translate('guidedOnboarding.observabilityGuide.documentationLink', { - defaultMessage: 'Kubernetes documentation', + defaultMessage: 'Learn more', }), url: 'https://docs.elastic.co/en/integrations/kubernetes', }, @@ -28,7 +28,7 @@ export const observabilityConfig: GuideConfig = { { id: 'add_data', title: i18n.translate('guidedOnboarding.observabilityGuide.addDataStep.title', { - defaultMessage: 'Add data', + defaultMessage: 'Add and verify your data', }), integration: 'kubernetes', descriptionList: [ @@ -59,13 +59,13 @@ export const observabilityConfig: GuideConfig = { title: i18n.translate( 'guidedOnboarding.observabilityGuide.viewDashboardStep.manualCompletionPopoverTitle', { - defaultMessage: 'Explore the pre-built Kubernetes dashboards', + defaultMessage: 'Explore Kubernetes dashboards', } ), description: i18n.translate( 'guidedOnboarding.observabilityGuide.viewDashboardStep.manualCompletionPopoverDescription', { - defaultMessage: `Take your time to explore out-of-the-box dashboards that are included with the Kubernetes integration. When you're ready, you can access the next step of the guide in the button above.`, + defaultMessage: `Take your time to explore these pre-built dashboards included with the Kubernetes integration. When you’re ready, click the Setup guide button to continue.`, } ), readyToCompleteOnNavigation: true, diff --git a/src/plugins/guided_onboarding/public/constants/guides_config/security.ts b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts index d2f9b352b9d81..3930ab66220f0 100644 --- a/src/plugins/guided_onboarding/public/constants/guides_config/security.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts @@ -6,25 +6,34 @@ * Side Public License, v 1. */ +import { i18n } from '@kbn/i18n'; import type { GuideConfig } from '../../types'; export const securityConfig: GuideConfig = { - title: 'Get started with SIEM', + title: i18n.translate('guidedOnboarding.securityGuide.title', { + defaultMessage: 'Elastic Security guided setup', + }), guideName: 'Security', completedGuideRedirectLocation: { appID: 'security', path: '/app/security/dashboards', }, - description: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', + description: i18n.translate('guidedOnboarding.securityGuide.description', { + defaultMessage: `We'll help you get set up quickly, using Elastic's out-of-the-box integrations.`, + }), steps: [ { id: 'add_data', - title: 'Add and view your data', + title: i18n.translate('guidedOnboarding.securityGuide.addDataStep.title', { + defaultMessage: 'Add data with Elastic Defend', + }), descriptionList: [ - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', - 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', + i18n.translate('guidedOnboarding.securityGuide.addDataStep.description1', { + defaultMessage: 'Select the Elastic Defend integration to add your data.', + }), + i18n.translate('guidedOnboarding.securityGuide.addDataStep.description2', { + defaultMessage: 'Make sure your data looks good.', + }), ], integration: 'endpoint', location: { @@ -34,16 +43,27 @@ export const securityConfig: GuideConfig = { }, { id: 'rules', - title: 'Turn on rules', + title: i18n.translate('guidedOnboarding.securityGuide.rulesStep.title', { + defaultMessage: 'Turn on rules', + }), descriptionList: [ - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', - 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', + i18n.translate('guidedOnboarding.securityGuide.rulesStep.description1', { + defaultMessage: 'Load the prebuilt rules.', + }), + i18n.translate('guidedOnboarding.securityGuide.rulesStep.description2', { + defaultMessage: 'Select the rules that you want.', + }), ], manualCompletion: { - title: 'Manual completion step title', - description: - 'Mark the step complete by opening the panel and clicking the button "Mark done"', + title: i18n.translate('guidedOnboarding.securityGuide.rulesStep.manualCompletion.title', { + defaultMessage: 'Continue with the tour', + }), + description: i18n.translate( + 'guidedOnboarding.securityGuide.rulesStep.manualCompletion.description', + { + defaultMessage: 'After you’ve enabled the rules you want, click here to continue.', + } + ), }, location: { appID: 'securitySolutionUI', @@ -52,11 +72,16 @@ export const securityConfig: GuideConfig = { }, { id: 'alertsCases', - title: 'Alerts and cases', + title: i18n.translate('guidedOnboarding.securityGuide.alertsStep.title', { + defaultMessage: 'Manage alerts and cases', + }), descriptionList: [ - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', - 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', + i18n.translate('guidedOnboarding.securityGuide.alertsStep.description1', { + defaultMessage: 'View and triage alerts.', + }), + i18n.translate('guidedOnboarding.securityGuide.alertsStep.description2', { + defaultMessage: 'Create a case.', + }), ], location: { appID: 'securitySolutionUI', diff --git a/src/plugins/guided_onboarding/public/plugin.tsx b/src/plugins/guided_onboarding/public/plugin.tsx index 5d18eab0ad223..4cf5fa9749a07 100755 --- a/src/plugins/guided_onboarding/public/plugin.tsx +++ b/src/plugins/guided_onboarding/public/plugin.tsx @@ -13,7 +13,11 @@ import { I18nProvider } from '@kbn/i18n-react'; import { CoreSetup, CoreStart, Plugin, CoreTheme, ApplicationStart } from '@kbn/core/public'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types'; +import type { + AppPluginStartDependencies, + GuidedOnboardingPluginSetup, + GuidedOnboardingPluginStart, +} from './types'; import { GuidePanel } from './components'; import { ApiService, apiService } from './services/api'; @@ -25,22 +29,28 @@ export class GuidedOnboardingPlugin return {}; } - public start(core: CoreStart): GuidedOnboardingPluginStart { + public start( + core: CoreStart, + { cloud }: AppPluginStartDependencies + ): GuidedOnboardingPluginStart { const { chrome, http, theme, application } = core; // Initialize services apiService.setup(http); - chrome.navControls.registerExtension({ - order: 1000, - mount: (target) => - this.mount({ - targetDomElement: target, - theme$: theme.theme$, - api: apiService, - application, - }), - }); + // Guided onboarding UI is only available on cloud + if (cloud?.isCloudEnabled) { + chrome.navControls.registerExtension({ + order: 1000, + mount: (target) => + this.mount({ + targetDomElement: target, + theme$: theme.theme$, + api: apiService, + application, + }), + }); + } // Return methods that should be available to other plugins return { diff --git a/src/plugins/guided_onboarding/public/services/api.test.ts b/src/plugins/guided_onboarding/public/services/api.test.ts index 3503b68e5466c..2296304166648 100644 --- a/src/plugins/guided_onboarding/public/services/api.test.ts +++ b/src/plugins/guided_onboarding/public/services/api.test.ts @@ -108,7 +108,7 @@ describe('GuidedOnboarding ApiService', () => { }); describe('isGuideStepActive$', () => { - it('returns true if the step has been started', async (done) => { + it('returns true if the step has been started', (done) => { const updatedState: GuideState = { ...searchAddDataActiveState, steps: [ @@ -120,8 +120,7 @@ describe('GuidedOnboarding ApiService', () => { searchAddDataActiveState.steps[2], ], }; - await apiService.updateGuideState(updatedState, false); - + apiService.updateGuideState(updatedState, false); subscription = apiService .isGuideStepActive$(searchGuide, firstStep) .subscribe((isStepActive) => { @@ -131,8 +130,8 @@ describe('GuidedOnboarding ApiService', () => { }); }); - it('returns false if the step is not been started', async (done) => { - await apiService.updateGuideState(searchAddDataActiveState, false); + it('returns false if the step is not been started', (done) => { + apiService.updateGuideState(searchAddDataActiveState, false); subscription = apiService .isGuideStepActive$(searchGuide, firstStep) .subscribe((isStepActive) => { @@ -371,7 +370,7 @@ describe('GuidedOnboarding ApiService', () => { }); describe('isGuidedOnboardingActiveForIntegration$', () => { - it('returns true if the integration is part of the active step', async (done) => { + it('returns true if the integration is part of the active step', (done) => { httpClient.get.mockResolvedValue({ state: [securityAddDataInProgressState], }); @@ -385,7 +384,7 @@ describe('GuidedOnboarding ApiService', () => { }); }); - it('returns false if another integration is part of the active step', async (done) => { + it('returns false if another integration is part of the active step', (done) => { httpClient.get.mockResolvedValue({ state: [securityAddDataInProgressState], }); @@ -399,7 +398,7 @@ describe('GuidedOnboarding ApiService', () => { }); }); - it('returns false if no guide is active', async (done) => { + it('returns false if no guide is active', (done) => { httpClient.get.mockResolvedValue({ state: [noGuideActiveState], }); diff --git a/src/plugins/guided_onboarding/public/types.ts b/src/plugins/guided_onboarding/public/types.ts index a6536e3caf114..3ff0507c494dc 100755 --- a/src/plugins/guided_onboarding/public/types.ts +++ b/src/plugins/guided_onboarding/public/types.ts @@ -9,6 +9,7 @@ import { Observable } from 'rxjs'; import { HttpSetup } from '@kbn/core/public'; import type { GuideState, GuideId, GuideStepIds, StepStatus } from '@kbn/guided-onboarding'; +import type { CloudStart } from '@kbn/cloud-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface GuidedOnboardingPluginSetup {} @@ -17,6 +18,10 @@ export interface GuidedOnboardingPluginStart { guidedOnboardingApi?: GuidedOnboardingApi; } +export interface AppPluginStartDependencies { + cloud?: CloudStart; +} + export interface GuidedOnboardingApi { setup: (httpClient: HttpSetup) => void; fetchActiveGuideState$: () => Observable; diff --git a/src/plugins/guided_onboarding/tsconfig.json b/src/plugins/guided_onboarding/tsconfig.json index 4a024443419ad..2837b97459430 100644 --- a/src/plugins/guided_onboarding/tsconfig.json +++ b/src/plugins/guided_onboarding/tsconfig.json @@ -15,5 +15,6 @@ { "path": "../kibana_react/tsconfig.json" }, + { "path": "../../../x-pack/plugins/cloud/tsconfig.json" }, ] } diff --git a/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap b/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap index 3cc05cb41c6f9..53df35833013f 100644 --- a/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap +++ b/src/plugins/home/public/application/components/__snapshots__/home.test.tsx.snap @@ -28,8 +28,10 @@ exports[`home change home route should render a link to change the default route "integrations": true, }, }, + "navigateToUrl": [MockFunction], } } + isCloudEnabled={false} isDarkMode={false} />

@@ -37,8 +37,6 @@ exports[`AddData render 1`] = ` { addBasePath={addBasePathMock} application={applicationStartMock} isDarkMode={false} + isCloudEnabled={false} /> ); expect(component).toMatchSnapshot(); diff --git a/src/plugins/home/public/application/components/add_data/add_data.tsx b/src/plugins/home/public/application/components/add_data/add_data.tsx index 27f98a85ff4e8..a3cdbd9241020 100644 --- a/src/plugins/home/public/application/components/add_data/add_data.tsx +++ b/src/plugins/home/public/application/components/add_data/add_data.tsx @@ -29,9 +29,10 @@ interface Props { addBasePath: (path: string) => string; application: ApplicationStart; isDarkMode: boolean; + isCloudEnabled: boolean; } -export const AddData: FC = ({ addBasePath, application, isDarkMode }) => { +export const AddData: FC = ({ addBasePath, application, isDarkMode, isCloudEnabled }) => { const { trackUiMetric } = getServices(); const canAccessIntegrations = application.capabilities.navLinks.integrations; if (canAccessIntegrations) { @@ -59,26 +60,47 @@ export const AddData: FC = ({ addBasePath, application, isDarkMode }) =>

- + + {isCloudEnabled && ( + + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} + { + trackUiMetric(METRIC_TYPE.CLICK, 'guided_onboarding_link'); + }} + > + + + + )} {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} { trackUiMetric(METRIC_TYPE.CLICK, 'home_tutorial_directory'); createAppNavigationHandler('/app/integrations/browse')(event); }} + fullWidth > - + - + - + - + { const { chromeServiceMock, applicationServiceMock } = jest.requireActual('@kbn/core/public/mocks'); const { uiSettingsServiceMock } = jest.requireActual('@kbn/core-ui-settings-browser-mocks'); + const { cloudMock } = jest.requireActual('@kbn/cloud-plugin/public/mocks'); const uiSettingsMock = uiSettingsServiceMock.createSetupContract(); uiSettingsMock.get.mockReturnValue(false); return { getServices: () => ({ + cloud: cloudMock.createSetup(), chrome: chromeServiceMock.createStartContract(), application: applicationServiceMock.createStartContract(), trackUiMetric: jest.fn(), diff --git a/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx b/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx index e63676ca3ca72..c82b200dfb6bd 100644 --- a/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx +++ b/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx @@ -21,6 +21,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; +import { useHistory } from 'react-router-dom'; import { METRIC_TYPE } from '@kbn/analytics'; import { i18n } from '@kbn/i18n'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; @@ -45,9 +46,10 @@ const skipText = i18n.translate('home.guidedOnboarding.gettingStarted.skip.butto }); export const GettingStarted = () => { - const { application, trackUiMetric, chrome, guidedOnboardingService, http, uiSettings } = + const { application, trackUiMetric, chrome, guidedOnboardingService, http, uiSettings, cloud } = getServices(); const [guidesState, setGuidesState] = useState([]); + const history = useHistory(); useEffect(() => { chrome.setBreadcrumbs([ @@ -76,6 +78,12 @@ export const GettingStarted = () => { fetchGuidesState(); }, [fetchGuidesState]); + useEffect(() => { + if (cloud?.isCloudEnabled === false) { + return history.push('/'); + } + }, [cloud, history]); + const onSkip = () => { trackUiMetric(METRIC_TYPE.CLICK, 'guided_onboarding__skipped'); // disable welcome screen on the home page @@ -92,6 +100,7 @@ export const GettingStarted = () => { await guidedOnboardingService?.activateGuide(useCase as GuideId, guideState); // TODO error handling https://github.com/elastic/kibana/issues/139798 }; + return ( @@ -109,7 +118,7 @@ export const GettingStarted = () => { {['search', 'observability', 'observabilityLink', 'security'].map((useCase) => { if (useCase === 'observabilityLink') { return ( - + { ); } return ( - + ({ getServices: () => ({ getBasePath: () => 'path', @@ -23,6 +24,7 @@ jest.mock('../kibana_services', () => ({ setBreadcrumbs: () => {}, }, application: { + navigateToUrl: mockNavigateToUrl, capabilities: { navLinks: { integrations: mockHasIntegrationsPermission, @@ -59,6 +61,7 @@ describe('home', () => { return `base_path/${url}`; }, hasUserDataView: jest.fn(async () => true), + isCloudEnabled: false, }; }); @@ -230,6 +233,16 @@ describe('home', () => { expect(component.find(Welcome).exists()).toBe(false); }); + + test('should redirect to guided onboarding on Cloud instead of welcome screen', async () => { + const isCloudEnabled = true; + const hasUserDataView = jest.fn(async () => false); + + const component = await renderHome({ isCloudEnabled, hasUserDataView }); + + expect(component.find(Welcome).exists()).toBe(false); + expect(mockNavigateToUrl).toHaveBeenCalledTimes(1); + }); }); describe('isNewKibanaInstance', () => { diff --git a/src/plugins/home/public/application/components/home.tsx b/src/plugins/home/public/application/components/home.tsx index f6b579213d420..707ea99ad8af4 100644 --- a/src/plugins/home/public/application/components/home.tsx +++ b/src/plugins/home/public/application/components/home.tsx @@ -33,6 +33,7 @@ export interface HomeProps { localStorage: Storage; urlBasePath: string; hasUserDataView: () => Promise; + isCloudEnabled: boolean; } interface State { @@ -126,7 +127,7 @@ export class Home extends Component { } private renderNormal() { - const { addBasePath, solutions } = this.props; + const { addBasePath, solutions, isCloudEnabled } = this.props; const { application, trackUiMetric } = getServices(); const isDarkMode = getServices().uiSettings?.get('theme:darkMode') || false; const devTools = this.findDirectoryById('console'); @@ -148,7 +149,12 @@ export class Home extends Component { > - + { public render() { const { isLoading, isWelcomeEnabled, isNewKibanaInstance } = this.state; + const { isCloudEnabled } = this.props; + const { application } = getServices(); if (isWelcomeEnabled) { if (isLoading) { return this.renderLoading(); } if (isNewKibanaInstance) { + if (isCloudEnabled) { + application.navigateToUrl('./home#/getting_started'); + return; + } return this.renderWelcome(); } } diff --git a/src/plugins/home/public/application/components/home_app.js b/src/plugins/home/public/application/components/home_app.js index af7b1dec48669..a6cdfec3b62e9 100644 --- a/src/plugins/home/public/application/components/home_app.js +++ b/src/plugins/home/public/application/components/home_app.js @@ -79,6 +79,7 @@ export function HomeApp({ directories, solutions }) { localStorage={localStorage} urlBasePath={getBasePath()} hasUserDataView={() => dataViewsService.hasUserDataView()} + isCloudEnabled={isCloudEnabled} /> diff --git a/src/plugins/home/public/application/components/sample_data/index.tsx b/src/plugins/home/public/application/components/sample_data/index.tsx index 8ce7a32b66e08..316ba615ce818 100644 --- a/src/plugins/home/public/application/components/sample_data/index.tsx +++ b/src/plugins/home/public/application/components/sample_data/index.tsx @@ -45,7 +45,7 @@ export function SampleDataCard({ urlBasePath, onDecline, onConfirm }: Props) { description={ } footer={ diff --git a/src/plugins/home/public/application/kibana_services.ts b/src/plugins/home/public/application/kibana_services.ts index b622cf862f315..af0a94b232fe6 100644 --- a/src/plugins/home/public/application/kibana_services.ts +++ b/src/plugins/home/public/application/kibana_services.ts @@ -21,6 +21,7 @@ import { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import { DataViewsContract } from '@kbn/data-views-plugin/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; import { GuidedOnboardingApi } from '@kbn/guided-onboarding-plugin/public'; +import { CloudSetup } from '@kbn/cloud-plugin/public'; import { TutorialService } from '../services/tutorials'; import { AddDataService } from '../services/add_data'; import { FeatureCatalogueRegistry } from '../services/feature_catalogue'; @@ -51,6 +52,7 @@ export interface HomeKibanaServices { addDataService: AddDataService; welcomeService: WelcomeService; guidedOnboardingService?: GuidedOnboardingApi; + cloud?: CloudSetup; } let services: HomeKibanaServices | null = null; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index c85f920fca6e1..b7270058aae6c 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -105,6 +105,7 @@ export class HomePublicPlugin featureCatalogue: this.featuresCatalogueRegistry, welcomeService: this.welcomeService, guidedOnboardingService: guidedOnboarding.guidedOnboardingApi, + cloud, }); coreStart.chrome.docTitle.change( i18n.translate('home.pageTitle', { defaultMessage: 'Home' }) diff --git a/src/plugins/interactive_setup/server/elasticsearch_service.test.ts b/src/plugins/interactive_setup/server/elasticsearch_service.test.ts index 717c6bf56481a..bfc3f1b2daba5 100644 --- a/src/plugins/interactive_setup/server/elasticsearch_service.test.ts +++ b/src/plugins/interactive_setup/server/elasticsearch_service.test.ts @@ -86,7 +86,7 @@ describe('ElasticsearchService', () => { }); describe('#connectionStatus$', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); afterEach(() => jest.useRealTimers()); it('does not repeat ping request if have multiple subscriptions', async () => { diff --git a/src/plugins/kibana_utils/common/abort_utils.test.ts b/src/plugins/kibana_utils/common/abort_utils.test.ts index 0d34a7852fb44..a528f3e48476e 100644 --- a/src/plugins/kibana_utils/common/abort_utils.test.ts +++ b/src/plugins/kibana_utils/common/abort_utils.test.ts @@ -8,9 +8,10 @@ import { AbortError, abortSignalToPromise } from './abort_utils'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); -const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); +const flushPromises = () => + new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve)); describe('AbortUtils', () => { describe('AbortError', () => { diff --git a/src/plugins/kibana_utils/public/storage/hashed_item_store/hashed_item_store.test.ts b/src/plugins/kibana_utils/public/storage/hashed_item_store/hashed_item_store.test.ts index 20cc81bc3b75b..5148d1ad6c03f 100644 --- a/src/plugins/kibana_utils/public/storage/hashed_item_store/hashed_item_store.test.ts +++ b/src/plugins/kibana_utils/public/storage/hashed_item_store/hashed_item_store.test.ts @@ -109,7 +109,7 @@ describe('hashedItemStore', () => { beforeEach(() => { // Control time. - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); sessionStorage = new StubBrowserStorage(); hashedItemStore = new HashedItemStore(sessionStorage); @@ -199,7 +199,7 @@ describe('hashedItemStore', () => { beforeEach(() => { // Control time. - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); sessionStorage = new StubBrowserStorage(); hashedItemStore = new HashedItemStore(sessionStorage); @@ -350,7 +350,7 @@ describe('hashedItemStore', () => { beforeEach(() => { // Control time. - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); sessionStorage = new StubBrowserStorage(); hashedItemStore = new HashedItemStore(sessionStorage); }); diff --git a/src/plugins/newsfeed/public/plugin.test.ts b/src/plugins/newsfeed/public/plugin.test.ts index a082b81dc84be..2ab54026a4cfb 100644 --- a/src/plugins/newsfeed/public/plugin.test.ts +++ b/src/plugins/newsfeed/public/plugin.test.ts @@ -16,7 +16,7 @@ describe('Newsfeed plugin', () => { let plugin: NewsfeedPublicPlugin; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/src/plugins/telemetry/public/services/telemetry_sender.test.ts b/src/plugins/telemetry/public/services/telemetry_sender.test.ts index 7f986af97331d..b68ab85f0340f 100644 --- a/src/plugins/telemetry/public/services/telemetry_sender.test.ts +++ b/src/plugins/telemetry/public/services/telemetry_sender.test.ts @@ -246,7 +246,7 @@ describe('TelemetrySender', () => { beforeEach(() => { window.fetch = mockFetch = jest.fn(); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); consoleWarnMock = jest.spyOn(global.console, 'warn').mockImplementation(() => {}); }); @@ -380,7 +380,7 @@ describe('TelemetrySender', () => { }); describe('getRetryDelay', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); it('sets a minimum retry delay of 60 seconds', () => { @@ -399,7 +399,7 @@ describe('TelemetrySender', () => { }); describe('startChecking', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); it('calls sendIfDue every 60000 ms', () => { diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts index 3c87857591e69..b303f8b4c3a19 100644 --- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts @@ -44,7 +44,7 @@ const reset = () => { executeFn.mockReset(); openContextMenuSpy.mockReset(); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }; beforeEach(reset); diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 26b5c1770ee8a..8426275f10dfd 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -436,6 +436,7 @@ export const QueryBarTopRow = React.memo( size={shouldShowDatePickerAsBadge() ? 's' : 'm'} color={props.isDirty ? 'success' : 'primary'} fill={props.isDirty} + needsUpdate={props.isDirty} data-test-subj="querySubmitButton" // @ts-expect-error Need to fix expecting `children` in EUI toolTipProps={{ diff --git a/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx b/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx index dbf7af6afe12d..f6f433de9fcf1 100644 --- a/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx @@ -28,7 +28,7 @@ import { QueryLanguageSwitcher } from './language_switcher'; import QueryStringInput from './query_string_input'; import { unifiedSearchPluginMock } from '../mocks'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); const startMock = coreMock.createStart(); const noop = () => { diff --git a/src/plugins/vis_types/table/public/utils/use/use_ui_state.test.ts b/src/plugins/vis_types/table/public/utils/use/use_ui_state.test.ts index 5d6d0594e8e62..6be4eeca6bdc3 100644 --- a/src/plugins/vis_types/table/public/utils/use/use_ui_state.test.ts +++ b/src/plugins/vis_types/table/public/utils/use/use_ui_state.test.ts @@ -95,7 +95,7 @@ describe('useUiState', () => { describe('updating uiState through callbacks', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); it('should update the uiState with new sort', async () => { diff --git a/src/plugins/vis_types/timeseries/public/application/components/series_editor.js b/src/plugins/vis_types/timeseries/public/application/components/series_editor.js index 7bd72b85edc1d..531075b36244b 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/series_editor.js +++ b/src/plugins/vis_types/timeseries/public/application/components/series_editor.js @@ -65,6 +65,10 @@ export class SeriesEditor extends Component { } }; + handleSeriesChange = (doc) => { + handleChange(this.props, doc); + }; + render() { const { limit, model, name, fields, colorPicker } = this.props; const list = model[name].filter((val, index) => index < (limit || Infinity)); @@ -89,7 +93,7 @@ export class SeriesEditor extends Component { disableDelete={model[name].length < 2} fields={fields} onAdd={() => handleAdd(this.props, newSeriesFn)} - onChange={(doc) => handleChange(this.props, doc)} + onChange={this.handleSeriesChange} onClone={() => this.handleClone(row)} onDelete={() => handleDelete(this.props, row)} model={row} diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js index 48ba0e5403665..506ce0dbdf2a9 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js @@ -35,7 +35,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { getDefaultQueryLanguage } from '../../lib/get_default_query_language'; import { checkIfNumericMetric } from '../../lib/check_if_numeric_metric'; import { QueryBarWrapper } from '../../query_bar_wrapper'; -import { DATA_FORMATTERS } from '../../../../../common/enums'; +import { DATA_FORMATTERS, BUCKET_TYPES } from '../../../../../common/enums'; import { isConfigurationFeatureEnabled } from '../../../../../common/check_ui_restrictions'; import { filterCannotBeAppliedErrorMessage } from '../../../../../common/errors'; import { tsvbEditorRowStyles } from '../../../styles/common.styles'; @@ -50,13 +50,20 @@ class TableSeriesConfigUi extends Component { } } + handleAggregateByChange = (selectedOptions) => { + this.props.onChange({ + aggregate_by: selectedOptions?.[0], + }); + }; + + handleSelectChange = createSelectHandler(this.props.onChange); + handleTextChange = createTextHandler(this.props.onChange); + changeModelFormatter = (formatter) => this.props.onChange({ formatter }); render() { const defaults = { offset_time: '', value_template: '{{value}}' }; const model = { ...defaults, ...this.props.model }; - const handleSelectChange = createSelectHandler(this.props.onChange); - const handleTextChange = createTextHandler(this.props.onChange); const htmlId = htmlIdGenerator(); const functionOptions = [ @@ -160,7 +167,7 @@ class TableSeriesConfigUi extends Component { fullWidth > - + @@ -222,11 +229,7 @@ class TableSeriesConfigUi extends Component { fields={this.props.fields} indexPattern={this.props.panel.index_pattern} value={model.aggregate_by} - onChange={(value) => - this.props.onChange({ - aggregate_by: value?.[0], - }) - } + onChange={this.handleAggregateByChange} fullWidth restrict={[ KBN_FIELD_TYPES.NUMBER, @@ -236,7 +239,7 @@ class TableSeriesConfigUi extends Component { KBN_FIELD_TYPES.STRING, ]} uiRestrictions={this.props.uiRestrictions} - type={'terms'} + type={BUCKET_TYPES.TERMS} /> @@ -251,9 +254,10 @@ class TableSeriesConfigUi extends Component { fullWidth > diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts index cbc899981717b..9943cfa627e23 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts @@ -6,10 +6,11 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { METRIC_TYPES } from '@kbn/data-plugin/public'; import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; import { TSVB_METRIC_TYPES } from '../../../common/enums'; -import { Metric } from '../../../common/types'; +import { Panel, Metric } from '../../../common/types'; import { convertToLens } from '.'; import { createPanel, createSeries } from '../lib/__mocks__'; import { AvgColumn } from '../lib/convert'; @@ -58,6 +59,10 @@ describe('convertToLens', () => { series: [createSeries({ metrics: [metric] })], }); + const vis = { + params: model, + } as Vis; + const metricColumn: AvgColumn = { columnId: 'col-id', dataType: 'number', @@ -89,51 +94,55 @@ describe('convertToLens', () => { test('should return null for invalid metrics', async () => { mockIsValidMetrics.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockIsValidMetrics).toBeCalledTimes(1); }); test('should return null for invalid or unsupported metrics', async () => { mockGetMetricsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetMetricsColumns).toBeCalledTimes(1); }); test('should return null for invalid or unsupported buckets', async () => { mockGetBucketsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetBucketsColumns).toBeCalledTimes(1); }); test('should return null if metric is staticValue', async () => { const result = await convertToLens({ - ...model, - series: [ - { - ...model.series[0], - metrics: [...model.series[0].metrics, { type: TSVB_METRIC_TYPES.STATIC } as Metric], - }, - ], - }); + params: { + ...model, + series: [ + { + ...model.series[0], + metrics: [...model.series[0].metrics, { type: TSVB_METRIC_TYPES.STATIC } as Metric], + }, + ], + }, + } as Vis); expect(result).toBeNull(); expect(mockGetDataSourceInfo).toBeCalledTimes(0); }); test('should return null if only series agg is specified', async () => { const result = await convertToLens({ - ...model, - series: [ - { - ...model.series[0], - metrics: [ - { type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min', id: 'some-id' } as Metric, - ], - }, - ], - }); + params: { + ...model, + series: [ + { + ...model.series[0], + metrics: [ + { type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min', id: 'some-id' } as Metric, + ], + }, + ], + }, + } as Vis); expect(result).toBeNull(); }); @@ -142,7 +151,7 @@ describe('convertToLens', () => { mockGetSeriesAgg.mockReturnValue({ metrics: [metric] }); mockGetConfigurationForGauge.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); }); @@ -151,8 +160,8 @@ describe('convertToLens', () => { mockGetSeriesAgg.mockReturnValue({ metrics: [metric] }); mockGetConfigurationForGauge.mockReturnValue({}); - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], @@ -163,8 +172,8 @@ describe('convertToLens', () => { hidden: false, }), ], - }) - ); + }), + } as Vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsMetric'); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts index b97f8d59e9537..87d5333d4be51 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts @@ -45,7 +45,10 @@ const getMaxFormula = (metric: Metric, column?: Column) => { }))`; }; -export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeRange) => { +export const convertToLens: ConvertTsvbToLensVisualization = async ( + { params: model }, + timeRange +) => { const dataViews = getDataViewsStart(); const series = model.series[0]; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.test.ts index 309f066b18f29..a97395f64c113 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import type { Panel } from '../../common/types'; import { convertTSVBtoLensConfiguration } from '.'; @@ -42,7 +43,9 @@ describe('convertTSVBtoLensConfiguration', () => { ...model, type: 'markdown', } as Panel; - const triggerOptions = await convertTSVBtoLensConfiguration(metricModel); + const triggerOptions = await convertTSVBtoLensConfiguration({ + params: metricModel, + } as Vis); expect(triggerOptions).toBeNull(); }); @@ -51,7 +54,9 @@ describe('convertTSVBtoLensConfiguration', () => { ...model, use_kibana_indexes: false, }; - const triggerOptions = await convertTSVBtoLensConfiguration(stringIndexPatternModel); + const triggerOptions = await convertTSVBtoLensConfiguration({ + params: stringIndexPatternModel, + } as Vis); expect(triggerOptions).toBeNull(); }); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts index a3d08e89e91a2..3e1982aa0903e 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { TimeRange } from '@kbn/data-plugin/common'; import type { Panel } from '../../common/types'; import { PANEL_TYPES } from '../../common/enums'; @@ -29,6 +30,10 @@ const getConvertFnByType = (type: PANEL_TYPES) => { const { convertToLens } = await import('./gauge'); return convertToLens; }, + [PANEL_TYPES.TABLE]: async () => { + const { convertToLens } = await import('./table'); + return convertToLens; + }, }; return convertionFns[type]?.(); @@ -39,17 +44,17 @@ const getConvertFnByType = (type: PANEL_TYPES) => { * Returns the Lens model, only if it is supported. If not, it returns null. * In case of null, the menu item is disabled and the user can't navigate to Lens. */ -export const convertTSVBtoLensConfiguration = async (model: Panel, timeRange?: TimeRange) => { +export const convertTSVBtoLensConfiguration = async (vis: Vis, timeRange?: TimeRange) => { // Disables the option for not supported charts, for the string mode and for series with annotations - if (!model.use_kibana_indexes) { + if (!vis.params.use_kibana_indexes) { return null; } // Disables if model is invalid - if (model.isModelInvalid) { + if (vis.params.isModelInvalid) { return null; } - const convertFn = await getConvertFnByType(model.type); + const convertFn = await getConvertFnByType(vis.params.type); - return (await convertFn?.(model, timeRange)) ?? null; + return (await convertFn?.(vis, timeRange)) ?? null; }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts index 9cb0238f9d265..0fabef6eebdbe 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts @@ -14,7 +14,7 @@ import { getConfigurationForMetric, getConfigurationForGauge } from '.'; const mockGetPalette = jest.fn(); -jest.mock('./palette', () => ({ +jest.mock('../palette', () => ({ getPalette: jest.fn(() => mockGetPalette()), })); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts index 7b49d604b2343..e6814b0797a1a 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts @@ -10,7 +10,7 @@ import color from 'color'; import { MetricVisConfiguration } from '@kbn/visualizations-plugin/common'; import { Panel } from '../../../../../common/types'; import { Column, Layer } from '../../convert'; -import { getPalette } from './palette'; +import { getPalette } from '../palette'; import { findMetricColumn, getMetricWithCollapseFn } from '../../../utils'; export const getConfigurationForMetric = ( diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.test.ts similarity index 99% rename from src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts rename to src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.test.ts index b7356f094f91a..059f0372c451a 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getPalette } from './palette'; +import { getPalette } from '.'; describe('getPalette', () => { const baseColor = '#fff'; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.ts similarity index 83% rename from src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts rename to src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.ts index 4079ffb396647..159804a1ea29b 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/palette/index.ts @@ -8,7 +8,7 @@ import color from 'color'; import { ColorStop, CustomPaletteParams, PaletteOutput } from '@kbn/coloring'; import { uniqBy } from 'lodash'; -import { Panel } from '../../../../../common/types'; +import { Panel, Series } from '../../../../../common/types'; const Operators = { GTE: 'gte', @@ -24,9 +24,11 @@ type ColorStopsWithMinMax = Pick< type MetricColorRules = Exclude; type GaugeColorRules = Exclude; +type SeriesColorRules = Exclude; type MetricColorRule = MetricColorRules[number]; type GaugeColorRule = GaugeColorRules[number]; +type SeriesColorRule = SeriesColorRules[number]; type ValidMetricColorRule = Omit & ( @@ -44,31 +46,47 @@ type ValidGaugeColorRule = Omit & { gauge: Exclude; }; +type ValidSeriesColorRule = Omit & { + text: Exclude; +}; + const isValidColorRule = ( rule: MetricColorRule | GaugeColorRule -): rule is ValidMetricColorRule | ValidGaugeColorRule => { +): rule is ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule => { const { background_color: bColor, color: textColor } = rule as MetricColorRule; const { gauge } = rule as GaugeColorRule; + const { text } = rule as SeriesColorRule; - return rule.operator && (bColor ?? textColor ?? gauge) && rule.value !== undefined ? true : false; + return Boolean( + rule.operator && (bColor ?? textColor ?? gauge ?? text) && rule.value !== undefined + ); }; const isMetricColorRule = ( - rule: ValidMetricColorRule | ValidGaugeColorRule + rule: ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule ): rule is ValidMetricColorRule => { const metricRule = rule as ValidMetricColorRule; return metricRule.background_color ?? metricRule.color ? true : false; }; -const getColor = (rule: ValidMetricColorRule | ValidGaugeColorRule) => { +const isGaugeColorRule = ( + rule: ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule +): rule is ValidGaugeColorRule => { + const metricRule = rule as ValidGaugeColorRule; + return Boolean(metricRule.gauge); +}; + +const getColor = (rule: ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule) => { if (isMetricColorRule(rule)) { return rule.background_color ?? rule.color; + } else if (isGaugeColorRule(rule)) { + return rule.gauge; } - return rule.gauge; + return rule.text; }; const getColorStopsWithMinMaxForAllGteOrWithLte = ( - rules: Array, + rules: Array, tailOperator: string, baseColor?: string ): ColorStopsWithMinMax => { @@ -125,7 +143,7 @@ const getColorStopsWithMinMaxForAllGteOrWithLte = ( }; const getColorStopsWithMinMaxForLtWithLte = ( - rules: Array + rules: Array ): ColorStopsWithMinMax => { const lastRule = rules[rules.length - 1]; const colorStops = rules.reduce((colors, rule, index, rulesArr) => { @@ -166,7 +184,7 @@ const getColorStopsWithMinMaxForLtWithLte = ( }; const getColorStopWithMinMaxForLte = ( - rule: ValidMetricColorRule | ValidGaugeColorRule + rule: ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule ): ColorStopsWithMinMax => { const colorStop = { color: color(getColor(rule)).hex(), @@ -183,7 +201,7 @@ const getColorStopWithMinMaxForLte = ( }; const getColorStopWithMinMaxForGte = ( - rule: ValidMetricColorRule | ValidGaugeColorRule, + rule: ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule, baseColor?: string ): ColorStopsWithMinMax => { const colorStop = { @@ -224,12 +242,14 @@ const getCustomPalette = ( }; export const getPalette = ( - rules: MetricColorRules | GaugeColorRules, + rules: MetricColorRules | GaugeColorRules | SeriesColorRules, baseColor?: string ): PaletteOutput | null | undefined => { - const validRules = (rules as Array).filter< - ValidMetricColorRule | ValidGaugeColorRule - >((rule): rule is ValidMetricColorRule | ValidGaugeColorRule => isValidColorRule(rule)); + const validRules = (rules as Array).filter< + ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule + >((rule): rule is ValidMetricColorRule | ValidGaugeColorRule | ValidSeriesColorRule => + isValidColorRule(rule) + ); validRules.sort((rule1, rule2) => { return rule1.value! - rule2.value!; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.test.ts new file mode 100644 index 0000000000000..6deeaaa39fb8f --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright 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 { createSeries } from '../../__mocks__'; +import { getColumnState } from '.'; + +const mockGetPalette = jest.fn(); + +jest.mock('../palette', () => ({ + getPalette: jest.fn(() => mockGetPalette()), +})); + +describe('getColumnState', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockGetPalette.mockReturnValue({ id: 'custom' }); + }); + + test('should return column state without palette if series is not provided', () => { + const config = getColumnState('test'); + expect(config).toEqual({ + columnId: 'test', + alignment: 'left', + colorMode: 'none', + }); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return column state with palette if series is provided', () => { + const config = getColumnState('test', undefined, createSeries()); + expect(config).toEqual({ + columnId: 'test', + alignment: 'left', + colorMode: 'text', + palette: { id: 'custom' }, + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); + + test('should return column state with collapseFn if collapseFn is provided', () => { + const config = getColumnState('test', 'max', createSeries()); + expect(config).toEqual({ + columnId: 'test', + alignment: 'left', + colorMode: 'text', + palette: { id: 'custom' }, + collapseFn: 'max', + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); +}); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.ts new file mode 100644 index 0000000000000..7f152fa218842 --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/table/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Series } from '../../../../../common/types'; +import { getPalette } from '../palette'; + +export const getColumnState = (columnId: string, collapseFn?: string, series?: Series) => { + const palette = series ? getPalette(series.color_rules ?? []) : undefined; + return { + columnId, + alignment: 'left' as const, + colorMode: palette ? 'text' : 'none', + ...(palette ? { palette } : {}), + ...(collapseFn ? { collapseFn } : {}), + }; +}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts index c06cc3e722279..2be4e09bf8898 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts @@ -32,7 +32,7 @@ interface ExtraColumnFields { const isSupportedFormat = (format: string) => ['bytes', 'number', 'percent'].includes(format); -export const getFormat = (series: Series): FormatParams => { +export const getFormat = (series: Pick): FormatParams => { let suffix; if (!series.formatter || series.formatter === 'default') { diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/date_histogram.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/date_histogram.ts index f2173cf56b469..0887ad1168ddf 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/date_histogram.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/date_histogram.ts @@ -9,28 +9,36 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import uuid from 'uuid'; import { DateHistogramParams, DataType } from '@kbn/visualizations-plugin/common/convert_to_lens'; -import { DateHistogramColumn } from './types'; -import type { Panel, Series } from '../../../../common/types'; +import { DateHistogramColumn, DateHistogramSeries } from './types'; +import type { Panel } from '../../../../common/types'; const getInterval = (interval?: string) => { return interval && !interval?.includes('=') ? interval : 'auto'; }; -export const convertToDateHistogramParams = (model: Panel, series: Series): DateHistogramParams => { +export const convertToDateHistogramParams = ( + model: Panel | undefined, + series: DateHistogramSeries, + includeEmptyRows: boolean = true +): DateHistogramParams => { return { - interval: getInterval(series.override_index_pattern ? series.series_interval : model.interval), + interval: getInterval(series.override_index_pattern ? series.series_interval : model?.interval), dropPartials: series.override_index_pattern ? series.series_drop_last_bucket > 0 - : model.drop_last_bucket > 0, - includeEmptyRows: true, + : (model?.drop_last_bucket ?? 0) > 0, + includeEmptyRows, }; }; export const convertToDateHistogramColumn = ( - model: Panel, - series: Series, + model: Panel | undefined, + series: DateHistogramSeries, dataView: DataView, - { fieldName, isSplit }: { fieldName: string; isSplit: boolean } + { + fieldName, + isSplit, + includeEmptyRows = true, + }: { fieldName: string; isSplit: boolean; includeEmptyRows?: boolean } ): DateHistogramColumn | null => { const dateField = dataView.getFieldByName(fieldName); @@ -38,7 +46,7 @@ export const convertToDateHistogramColumn = ( return null; } - const params = convertToDateHistogramParams(model, series); + const params = convertToDateHistogramParams(model, series, includeEmptyRows); return { columnId: uuid(), diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filters.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filters.ts index 9134504813b68..05d74337e848d 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filters.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filters.ts @@ -8,10 +8,9 @@ import uuid from 'uuid'; import { FiltersParams } from '@kbn/visualizations-plugin/common/convert_to_lens'; -import { FiltersColumn } from './types'; -import type { Series } from '../../../../common/types'; +import { FiltersColumn, FiltersSeries } from './types'; -export const convertToFiltersParams = (series: Series): FiltersParams => { +export const convertToFiltersParams = (series: FiltersSeries): FiltersParams => { const splitFilters = []; if (series.split_mode === 'filter' && series.filter) { splitFilters.push({ filter: series.filter }); @@ -35,7 +34,10 @@ export const convertToFiltersParams = (series: Series): FiltersParams => { }; }; -export const convertToFiltersColumn = (series: Series, isSplit: boolean): FiltersColumn | null => { +export const convertToFiltersColumn = ( + series: FiltersSeries, + isSplit: boolean +): FiltersColumn | null => { const params = convertToFiltersParams(series); if (!params.filters.length) { return null; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.test.ts index 907fe458c6a64..5d6dc036a7bd0 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.test.ts @@ -47,6 +47,11 @@ describe('convertToStaticValueColumn', () => { [{ series, metrics: [metric], dataView }, { visibleSeriesCount: 1 }], null, ], + [ + 'null if value is not specified', + [{ series, metrics: [metric], dataView }, { visibleSeriesCount: 2 }], + null, + ], [ 'static value column', [{ series, metrics: [{ ...metric, value: 'some value' }], dataView }], diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts index d3e6aef09b1cf..7990107bb5bf9 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts @@ -32,6 +32,9 @@ export const convertToStaticValueColumn = ( return null; } const currentMetric = metrics[metrics.length - 1]; + if (!currentMetric.value) { + return null; + } return { operationType: 'static_value', references: [], @@ -68,7 +71,10 @@ export const convertStaticValueToFormulaColumn = ( return null; } const currentMetric = metrics[metrics.length - 1]; - return createFormulaColumn(currentMetric.value ?? '', { + if (!currentMetric.value) { + return null; + } + return createFormulaColumn(currentMetric.value, { series, metric: currentMetric, dataView, diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts index 977de1947d4f8..c31d8dca68ced 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts @@ -9,16 +9,15 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import { DataType, TermsParams } from '@kbn/visualizations-plugin/common'; import uuid from 'uuid'; -import { Series } from '../../../../common/types'; import { excludeMetaFromColumn, getFormat, isColumnWithMeta } from './column'; -import { Column, TermsColumn } from './types'; +import { Column, TermsColumn, TermsSeries } from './types'; interface OrderByWithAgg { orderAgg?: TermsParams['orderAgg']; orderBy: TermsParams['orderBy']; } -const getOrderByWithAgg = (series: Series, columns: Column[]): OrderByWithAgg | null => { +const getOrderByWithAgg = (series: TermsSeries, columns: Column[]): OrderByWithAgg | null => { if (series.terms_order_by === '_key') { return { orderBy: { type: 'alphabetical' } }; } @@ -56,7 +55,7 @@ const getOrderByWithAgg = (series: Series, columns: Column[]): OrderByWithAgg | }; export const convertToTermsParams = ( - series: Series, + series: TermsSeries, columns: Column[], secondaryFields: string[] ): TermsParams | null => { @@ -84,10 +83,11 @@ export const convertToTermsParams = ( export const convertToTermsColumn = ( termFields: [string, ...string[]], - series: Series, + series: TermsSeries, columns: Column[], dataView: DataView, - isSplit: boolean = false + isSplit: boolean = false, + label?: string ): TermsColumn | null => { const [baseField, ...secondaryFields] = termFields; const field = dataView.getFieldByName(baseField); @@ -108,6 +108,7 @@ export const convertToTermsColumn = ( sourceField: field.name, isBucketed: true, isSplit, + label, params: { ...params, ...getFormat(series) }, }; }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts index 4b3b6c582f915..943550aee0066 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts @@ -117,4 +117,24 @@ export interface CommonColumnConverterArgs { dataView: DataView; } +export type TermsSeries = Pick< + Series, + | 'split_mode' + | 'terms_direction' + | 'terms_order_by' + | 'terms_size' + | 'terms_include' + | 'terms_exclude' + | 'terms_field' + | 'formatter' + | 'value_template' +>; + +export type FiltersSeries = Pick; + +export type DateHistogramSeries = Pick< + Series, + 'split_mode' | 'override_index_pattern' | 'series_interval' | 'series_drop_last_bucket' +>; + export { FiltersColumn, TermsColumn, DateHistogramColumn }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts index debe064940c8e..a2130de36abd4 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts @@ -68,6 +68,7 @@ const supportedPanelTypes: readonly PANEL_TYPES[] = [ PANEL_TYPES.TOP_N, PANEL_TYPES.METRIC, PANEL_TYPES.GAUGE, + PANEL_TYPES.TABLE, ]; const supportedTimeRangeModes: readonly TIME_RANGE_DATA_MODES[] = [ diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts index c0aa201de6837..8ca184d443a68 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts @@ -7,18 +7,21 @@ */ import type { DataView } from '@kbn/data-views-plugin/common'; -import { Series, Panel } from '../../../../common/types'; +import { Panel } from '../../../../common/types'; import { getFieldsForTerms } from '../../../../common/fields_utils'; import { Column, convertToFiltersColumn, convertToDateHistogramColumn, convertToTermsColumn, + TermsSeries, + FiltersSeries, + DateHistogramSeries, } from '../convert'; import { getValidColumns } from './columns'; export const isSplitWithDateHistogram = ( - series: Series, + series: TermsSeries, splitFields: string[], dataView: DataView ) => { @@ -39,27 +42,49 @@ export const isSplitWithDateHistogram = ( return false; }; +const isFiltersSeries = ( + series: DateHistogramSeries | TermsSeries | FiltersSeries +): series is FiltersSeries => { + return series.split_mode === 'filters' || series.split_mode === 'filter'; +}; + +const isTermsSeries = ( + series: DateHistogramSeries | TermsSeries | FiltersSeries +): series is TermsSeries => { + return series.split_mode === 'terms'; +}; + +const isDateHistogramSeries = ( + series: DateHistogramSeries | TermsSeries | FiltersSeries, + isDateHistogram: boolean +): series is DateHistogramSeries => { + return isDateHistogram && series.split_mode === 'terms'; +}; + export const getBucketsColumns = ( - model: Panel, - series: Series, + model: Panel | undefined, + series: DateHistogramSeries | TermsSeries | FiltersSeries, columns: Column[], dataView: DataView, - isSplit: boolean = false + isSplit: boolean = false, + label?: string, + includeEmptyRowsForDateHistogram: boolean = true ) => { - if (series.split_mode === 'filters' || series.split_mode === 'filter') { + if (isFiltersSeries(series)) { const filterColumn = convertToFiltersColumn(series, true); return getValidColumns([filterColumn]); } - if (series.split_mode === 'terms') { + if (isTermsSeries(series)) { const splitFields = getFieldsForTerms(series.terms_field); const isDateHistogram = isSplitWithDateHistogram(series, splitFields, dataView); if (isDateHistogram === null) { return null; } - if (isDateHistogram) { + if (isDateHistogramSeries(series, isDateHistogram)) { const dateHistogramColumn = convertToDateHistogramColumn(model, series, dataView, { fieldName: splitFields[0], isSplit: true, + includeEmptyRows: includeEmptyRowsForDateHistogram, }); return getValidColumns(dateHistogramColumn); } @@ -73,7 +98,8 @@ export const getBucketsColumns = ( series, columns, dataView, - isSplit + isSplit, + label ); return getValidColumns(termsColumn); } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.test.ts index 9407599573d9d..6d62994be4447 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.test.ts @@ -6,10 +6,12 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { METRIC_TYPES } from '@kbn/data-plugin/public'; import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; import { convertToLens } from '.'; import { createPanel, createSeries } from '../lib/__mocks__'; +import { Panel } from '../../../common/types'; const mockGetMetricsColumns = jest.fn(); const mockGetBucketsColumns = jest.fn(); @@ -54,6 +56,10 @@ describe('convertToLens', () => { ], }); + const vis = { + params: model, + } as Vis; + const bucket = { isBucketed: true, isSplit: true, @@ -135,27 +141,27 @@ describe('convertToLens', () => { test('should return null for invalid metrics', async () => { mockIsValidMetrics.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockIsValidMetrics).toBeCalledTimes(1); }); test('should return null for invalid or unsupported metrics', async () => { mockGetMetricsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetMetricsColumns).toBeCalledTimes(1); }); test('should return null for invalid or unsupported buckets', async () => { mockGetBucketsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetBucketsColumns).toBeCalledTimes(1); }); test('should return state for valid model', async () => { - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsMetric'); expect(mockGetBucketsColumns).toBeCalledTimes(model.series.length); @@ -163,16 +169,16 @@ describe('convertToLens', () => { }); test('should skip hidden series', async () => { - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], hidden: true, }), ], - }) - ); + }), + } as Vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsMetric'); expect(mockIsValidMetrics).toBeCalledTimes(0); @@ -185,8 +191,8 @@ describe('convertToLens', () => { indexPattern: { id: 'test-index-pattern-1' }, }); - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], @@ -197,8 +203,8 @@ describe('convertToLens', () => { hidden: false, }), ], - }) - ); + }), + } as Vis); expect(result).toBeNull(); }); @@ -207,8 +213,8 @@ describe('convertToLens', () => { mockGetBucketsColumns.mockReturnValueOnce([]); mockGetMetricsColumns.mockReturnValueOnce([metric]); - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], @@ -219,8 +225,8 @@ describe('convertToLens', () => { hidden: false, }), ], - }) - ); + }), + } as Vis); expect(result).toBeNull(); }); @@ -229,8 +235,8 @@ describe('convertToLens', () => { mockGetBucketsColumns.mockReturnValueOnce([bucket2]); mockGetMetricsColumns.mockReturnValueOnce([metric]); - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], @@ -241,8 +247,8 @@ describe('convertToLens', () => { hidden: false, }), ], - }) - ); + }), + } as Vis); expect(result).toBeNull(); }); @@ -251,8 +257,8 @@ describe('convertToLens', () => { mockGetBucketsColumns.mockReturnValueOnce([bucket]); mockGetMetricsColumns.mockReturnValueOnce([metric]); - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], @@ -263,8 +269,8 @@ describe('convertToLens', () => { hidden: false, }), ], - }) - ); + }), + } as Vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsMetric'); expect(mockGetConfigurationForMetric).toBeCalledTimes(1); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts index 149acc513b9ff..fbf04a2dcf779 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts @@ -22,7 +22,10 @@ import { excludeMetaFromLayers, getUniqueBuckets } from '../utils'; const MAX_SERIES = 2; const MAX_BUCKETS = 2; -export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeRange) => { +export const convertToLens: ConvertTsvbToLensVisualization = async ( + { params: model }, + timeRange +) => { const dataViews = getDataViewsStart(); const seriesNum = model.series.filter((series) => !series.hidden).length; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.test.ts new file mode 100644 index 0000000000000..37676b302fba1 --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.test.ts @@ -0,0 +1,235 @@ +/* + * Copyright 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 { TableVisConfiguration } from '@kbn/visualizations-plugin/common'; +import { Vis } from '@kbn/visualizations-plugin/public'; +import { METRIC_TYPES } from '@kbn/data-plugin/public'; +import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; +import { convertToLens } from '.'; +import { createPanel, createSeries } from '../lib/__mocks__'; +import { Panel } from '../../../common/types'; +import { TSVB_METRIC_TYPES } from '../../../common/enums'; + +const mockConvertToDateHistogramColumn = jest.fn(); +const mockGetMetricsColumns = jest.fn(); +const mockGetBucketsColumns = jest.fn(); +const mockGetConfigurationForTimeseries = jest.fn(); +const mockIsValidMetrics = jest.fn(); +const mockGetDatasourceValue = jest + .fn() + .mockImplementation(() => Promise.resolve(stubLogstashDataView)); +const mockGetDataSourceInfo = jest.fn(); +const mockGetColumnState = jest.fn(); + +jest.mock('../../services', () => ({ + getDataViewsStart: jest.fn(() => mockGetDatasourceValue), +})); + +jest.mock('../lib/convert', () => ({ + excludeMetaFromColumn: jest.fn().mockReturnValue({}), +})); + +jest.mock('../lib/series', () => ({ + getMetricsColumns: jest.fn(() => mockGetMetricsColumns()), + getBucketsColumns: jest.fn(() => mockGetBucketsColumns()), +})); + +jest.mock('../lib/configurations/table', () => ({ + getColumnState: jest.fn(() => mockGetColumnState()), +})); + +jest.mock('../lib/metrics', () => ({ + isValidMetrics: jest.fn(() => mockIsValidMetrics()), + getReducedTimeRange: jest.fn().mockReturnValue('10'), +})); + +jest.mock('../lib/datasource', () => ({ + getDataSourceInfo: jest.fn(() => mockGetDataSourceInfo()), +})); + +describe('convertToLens', () => { + const model = createPanel({ + series: [ + createSeries({ + metrics: [ + { id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }, + { id: 'some-id-1', type: METRIC_TYPES.COUNT }, + ], + }), + ], + }); + + const vis = { + params: model, + uiState: { + get: () => ({}), + }, + } as Vis; + + beforeEach(() => { + mockIsValidMetrics.mockReturnValue(true); + mockGetDataSourceInfo.mockReturnValue({ + indexPatternId: 'test-index-pattern', + timeField: 'timeField', + indexPattern: { id: 'test-index-pattern' }, + }); + mockConvertToDateHistogramColumn.mockReturnValue({}); + mockGetMetricsColumns.mockReturnValue([{}]); + mockGetBucketsColumns.mockReturnValue([{}]); + mockGetConfigurationForTimeseries.mockReturnValue({ layers: [] }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should return null for invalid metrics', async () => { + mockIsValidMetrics.mockReturnValue(null); + const result = await convertToLens(vis); + expect(result).toBeNull(); + expect(mockIsValidMetrics).toBeCalledTimes(1); + }); + + test('should return null for invalid or unsupported metrics', async () => { + mockGetMetricsColumns.mockReturnValue(null); + const result = await convertToLens(vis); + expect(result).toBeNull(); + expect(mockGetMetricsColumns).toBeCalledTimes(1); + }); + + test('should return null if several series have different “Field” + “Aggregate function”', async () => { + const result = await convertToLens({ + params: createPanel({ + series: [createSeries({ aggregate_by: 'new' }), createSeries({ aggregate_by: 'test' })], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeNull(); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + }); + + test('should return null if “Aggregate function” is not supported', async () => { + const result = await convertToLens({ + params: createPanel({ + series: [createSeries({ aggregate_by: 'new', aggregate_function: 'cumulative_sum' })], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeNull(); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + }); + + test('should return null if model have not visible metrics', async () => { + const result = await convertToLens({ + params: createPanel({ + series: [ + createSeries({ + metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], + hidden: true, + }), + ], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeNull(); + }); + + test('should return null if only static value is visible metric', async () => { + mockGetMetricsColumns.mockReturnValue([ + { columnId: 'metric-column-1', operationType: 'static_value' }, + ]); + const result = await convertToLens({ + params: createPanel({ + series: [ + createSeries({ + metrics: [{ id: 'some-id', type: TSVB_METRIC_TYPES.STATIC }], + hidden: true, + }), + ], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeNull(); + }); + + test('should return state for valid model', async () => { + const result = await convertToLens(vis); + expect(result).toBeDefined(); + expect(result?.type).toBe('lnsDatatable'); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + // every series + group by + expect(mockGetColumnState).toBeCalledTimes(model.series.length + 1); + }); + + test('should return state for valid model with “Field” + “Aggregate function”', async () => { + const result = await convertToLens({ + params: createPanel({ + series: [createSeries({ aggregate_by: 'new', aggregate_function: 'sum' })], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeDefined(); + expect(result?.type).toBe('lnsDatatable'); + expect(mockGetBucketsColumns).toBeCalledTimes(2); + // every series + group by + (“Field” + “Aggregate function”) + expect(mockGetColumnState).toBeCalledTimes(model.series.length + 2); + }); + + test('should return correct sorting config', async () => { + mockGetMetricsColumns.mockReturnValue([{ columnId: 'metric-column-1' }]); + const result = await convertToLens({ + params: createPanel({ + series: [createSeries({ id: 'test' })], + }), + uiState: { + get: () => ({ sort: { order: 'decs', column: 'test' } }), + }, + } as Vis); + expect(result).toBeDefined(); + expect(result?.type).toBe('lnsDatatable'); + expect((result?.configuration as TableVisConfiguration).sorting).toEqual({ + direction: 'decs', + columnId: 'metric-column-1', + }); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + // every series + group by + expect(mockGetColumnState).toBeCalledTimes(model.series.length + 1); + }); + + test('should skip hidden series', async () => { + const result = await convertToLens({ + params: createPanel({ + series: [ + createSeries({ + metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], + hidden: true, + }), + createSeries({ + metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], + }), + ], + }), + uiState: { + get: () => ({}), + }, + } as Vis); + expect(result).toBeDefined(); + expect(result?.type).toBe('lnsDatatable'); + expect(mockIsValidMetrics).toBeCalledTimes(1); + }); +}); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.ts new file mode 100644 index 0000000000000..0219d1080724b --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/table/index.ts @@ -0,0 +1,183 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 uuid from 'uuid'; +import { parseTimeShift } from '@kbn/data-plugin/common'; +import { getIndexPatternIds, Layer } from '@kbn/visualizations-plugin/common/convert_to_lens'; +import { PANEL_TYPES } from '../../../common/enums'; +import { getDataViewsStart } from '../../services'; +import { getColumnState } from '../lib/configurations/table'; +import { getDataSourceInfo } from '../lib/datasource'; +import { getMetricsColumns, getBucketsColumns } from '../lib/series'; +import { getReducedTimeRange, isValidMetrics } from '../lib/metrics'; +import { ConvertTsvbToLensVisualization } from '../types'; +import { Layer as ExtendedLayer, excludeMetaFromColumn, Column } from '../lib/convert'; + +const excludeMetaFromLayers = (layers: Record): Record => { + const newLayers: Record = {}; + Object.entries(layers).forEach(([layerId, layer]) => { + const columns = layer.columns.map(excludeMetaFromColumn); + newLayers[layerId] = { ...layer, columns }; + }); + + return newLayers; +}; + +export const convertToLens: ConvertTsvbToLensVisualization = async ( + { params: model, uiState }, + timeRange +) => { + const columnStates = []; + const dataViews = getDataViewsStart(); + const seriesNum = model.series.filter((series) => !series.hidden).length; + const sortConfig = uiState.get('table')?.sort ?? {}; + + const datasourceInfo = await getDataSourceInfo( + model.index_pattern, + model.time_field, + false, + undefined, + undefined, + dataViews + ); + + if (!datasourceInfo) { + return null; + } + + const { indexPatternId, indexPattern } = datasourceInfo; + + const commonBucketsColumns = getBucketsColumns( + undefined, + { + split_mode: 'terms', + terms_field: model.pivot_id, + terms_size: model.pivot_rows ? model.pivot_rows.toString() : undefined, + }, + [], + indexPattern!, + false, + model.pivot_label, + false + ); + + if (!commonBucketsColumns) { + return null; + } + + const sortConfiguration = { + columnId: commonBucketsColumns[0].columnId, + direction: sortConfig.order, + }; + + columnStates.push(getColumnState(commonBucketsColumns[0].columnId)); + + let bucketsColumns: Column[] | null = []; + + if ( + !model.series.every( + (s) => + ((!s.aggregate_by && !model.series[0].aggregate_by) || + s.aggregate_by === model.series[0].aggregate_by) && + ((!s.aggregate_function && !model.series[0].aggregate_function) || + s.aggregate_function === model.series[0].aggregate_function) + ) + ) { + return null; + } + + if (model.series[0].aggregate_by) { + if ( + !model.series[0].aggregate_function || + !['sum', 'mean', 'min', 'max'].includes(model.series[0].aggregate_function) + ) { + return null; + } + bucketsColumns = getBucketsColumns( + undefined, + { + split_mode: 'terms', + terms_field: model.series[0].aggregate_by, + }, + [], + indexPattern!, + false + ); + if (bucketsColumns === null) { + return null; + } + + columnStates.push( + getColumnState( + bucketsColumns[0].columnId, + model.series[0].aggregate_function === 'mean' ? 'avg' : model.series[0].aggregate_function + ) + ); + } + + const metrics = []; + + // handle multiple layers/series + for (const [_, series] of model.series.entries()) { + if (series.hidden) { + continue; + } + + // not valid time shift + if (series.offset_time && parseTimeShift(series.offset_time) === 'invalid') { + return null; + } + + if (!isValidMetrics(series.metrics, PANEL_TYPES.TABLE, series.time_range_mode)) { + return null; + } + + const reducedTimeRange = getReducedTimeRange(model, series, timeRange); + + // handle multiple metrics + const metricsColumns = getMetricsColumns(series, indexPattern!, seriesNum, { + reducedTimeRange, + }); + if (!metricsColumns) { + return null; + } + + columnStates.push(getColumnState(metricsColumns[0].columnId, undefined, series)); + + if (sortConfig.column === series.id) { + sortConfiguration.columnId = metricsColumns[0].columnId; + } + + metrics.push(...metricsColumns); + } + + if (!metrics.length || metrics.every((metric) => metric.operationType === 'static_value')) { + return null; + } + + const extendedLayer: ExtendedLayer = { + indexPatternId: indexPatternId as string, + layerId: uuid(), + columns: [...metrics, ...commonBucketsColumns, ...bucketsColumns], + columnOrder: [], + }; + + const layers = Object.values(excludeMetaFromLayers({ 0: extendedLayer })); + + return { + type: 'lnsDatatable', + layers, + configuration: { + columns: columnStates, + layerId: extendedLayer.layerId, + layerType: 'data', + sorting: sortConfiguration, + }, + indexPatternIds: getIndexPatternIds(layers), + }; +}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts index c81db38e05384..64fee3484b3b6 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts @@ -6,10 +6,12 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { METRIC_TYPES } from '@kbn/data-plugin/public'; import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; import { convertToLens } from '.'; import { createPanel, createSeries } from '../lib/__mocks__'; +import { Panel } from '../../../common/types'; const mockConvertToDateHistogramColumn = jest.fn(); const mockGetMetricsColumns = jest.fn(); @@ -60,6 +62,10 @@ describe('convertToLens', () => { ], }); + const vis = { + params: model, + } as Vis; + beforeEach(() => { mockIsValidMetrics.mockReturnValue(true); mockGetDataSourceInfo.mockReturnValue({ @@ -79,35 +85,35 @@ describe('convertToLens', () => { test('should return null for invalid metrics', async () => { mockIsValidMetrics.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockIsValidMetrics).toBeCalledTimes(1); }); test('should return null for empty time field', async () => { mockGetDataSourceInfo.mockReturnValue({ timeField: null }); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetDataSourceInfo).toBeCalledTimes(1); }); test('should return null for invalid date histogram', async () => { mockConvertToDateHistogramColumn.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockConvertToDateHistogramColumn).toBeCalledTimes(1); }); test('should return null for invalid or unsupported metrics', async () => { mockGetMetricsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetMetricsColumns).toBeCalledTimes(1); }); test('should return null for invalid or unsupported buckets', async () => { mockGetBucketsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetBucketsColumns).toBeCalledTimes(1); }); @@ -119,14 +125,14 @@ describe('convertToLens', () => { operationType: 'static_value', }, ]); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetMetricsColumns).toBeCalledTimes(1); expect(mockGetBucketsColumns).toBeCalledTimes(1); }); test('should return state for valid model', async () => { - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsXY'); expect(mockGetBucketsColumns).toBeCalledTimes(model.series.length); @@ -134,16 +140,16 @@ describe('convertToLens', () => { }); test('should skip hidden series', async () => { - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], hidden: true, }), ], - }) - ); + }), + } as Vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsXY'); expect(mockIsValidMetrics).toBeCalledTimes(0); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts index ef678fcc2dab4..a08b7113c4a7b 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts @@ -14,7 +14,6 @@ import { } from '@kbn/visualizations-plugin/common/convert_to_lens'; import uuid from 'uuid'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { Panel } from '../../../common/types'; import { PANEL_TYPES } from '../../../common/enums'; import { getDataViewsStart } from '../../services'; import { getDataSourceInfo } from '../lib/datasource'; @@ -41,7 +40,7 @@ const excludeMetaFromLayers = (layers: Record): Record { +export const convertToLens: ConvertTsvbToLensVisualization = async ({ params: model }) => { const dataViews: DataViewsPublicPluginStart = getDataViewsStart(); const extendedLayers: Record = {}; const seriesNum = model.series.filter((series) => !series.hidden).length; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.test.ts index 7e4776f10ac9f..646323a6691d5 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.test.ts @@ -6,10 +6,12 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { METRIC_TYPES } from '@kbn/data-plugin/public'; import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; import { convertToLens } from '.'; import { createPanel, createSeries } from '../lib/__mocks__'; +import { Panel } from '../../../common/types'; const mockGetMetricsColumns = jest.fn(); const mockGetBucketsColumns = jest.fn(); @@ -59,6 +61,10 @@ describe('convertToLens', () => { ], }); + const vis = { + params: model, + } as Vis; + beforeEach(() => { mockIsValidMetrics.mockReturnValue(true); mockGetDataSourceInfo.mockReturnValue({ @@ -77,27 +83,27 @@ describe('convertToLens', () => { test('should return null for invalid metrics', async () => { mockIsValidMetrics.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockIsValidMetrics).toBeCalledTimes(1); }); test('should return null for invalid or unsupported metrics', async () => { mockGetMetricsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetMetricsColumns).toBeCalledTimes(1); }); test('should return null for invalid or unsupported buckets', async () => { mockGetBucketsColumns.mockReturnValue(null); - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeNull(); expect(mockGetBucketsColumns).toBeCalledTimes(1); }); test('should return state for valid model', async () => { - const result = await convertToLens(model); + const result = await convertToLens(vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsXY'); expect(mockGetBucketsColumns).toBeCalledTimes(model.series.length); @@ -105,16 +111,16 @@ describe('convertToLens', () => { }); test('should skip hidden series', async () => { - const result = await convertToLens( - createPanel({ + const result = await convertToLens({ + params: createPanel({ series: [ createSeries({ metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], hidden: true, }), ], - }) - ); + }), + } as Vis); expect(result).toBeDefined(); expect(result?.type).toBe('lnsXY'); expect(mockIsValidMetrics).toBeCalledTimes(0); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts index 130646f72f127..9505b7f5f0c7e 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts @@ -28,7 +28,10 @@ const excludeMetaFromLayers = (layers: Record): Record { +export const convertToLens: ConvertTsvbToLensVisualization = async ( + { params: model }, + timeRange +) => { const dataViews = getDataViewsStart(); const extendedLayers: Record = {}; const seriesNum = model.series.filter((series) => !series.hidden).length; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts index 69a90c7864eb3..9f00a669ea5c3 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts @@ -6,18 +6,22 @@ * Side Public License, v 1. */ +import { Vis } from '@kbn/visualizations-plugin/public'; import { MetricVisConfiguration, NavigateToLensContext, XYConfiguration, + TableVisConfiguration, } from '@kbn/visualizations-plugin/common'; import { TimeRange } from '@kbn/data-plugin/common'; import type { Panel } from '../../common/types'; export type ConvertTsvbToLensVisualization = ( - model: Panel, + vis: Vis, timeRange?: TimeRange -) => Promise | null>; +) => Promise | null>; export interface Filter { kql?: string | { [key: string]: any } | undefined; diff --git a/src/plugins/vis_types/timeseries/public/metrics_type.ts b/src/plugins/vis_types/timeseries/public/metrics_type.ts index 3bf9f9b90bf1a..43be3ee3004f4 100644 --- a/src/plugins/vis_types/timeseries/public/metrics_type.ts +++ b/src/plugins/vis_types/timeseries/public/metrics_type.ts @@ -171,15 +171,13 @@ export const metricsVisDefinition: VisTypeDefinition< return { canNavigateToLens: Boolean( vis?.params - ? await convertTSVBtoLensConfiguration(vis.params as Panel, timeFilter?.getAbsoluteTime()) + ? await convertTSVBtoLensConfiguration(vis, timeFilter?.getAbsoluteTime()) : null ), }; }, navigateToLens: async (vis, timeFilter) => - vis?.params - ? await convertTSVBtoLensConfiguration(vis?.params as Panel, timeFilter?.getAbsoluteTime()) - : null, + vis?.params ? await convertTSVBtoLensConfiguration(vis, timeFilter?.getAbsoluteTime()) : null, inspectorAdapters: () => ({ requests: new RequestAdapter(), diff --git a/src/plugins/vis_types/vislib/public/vis_controller.tsx b/src/plugins/vis_types/vislib/public/vis_controller.tsx index af9dda7ccf01f..40a518a8c0c9b 100644 --- a/src/plugins/vis_types/vislib/public/vis_controller.tsx +++ b/src/plugins/vis_types/vislib/public/vis_controller.tsx @@ -9,13 +9,10 @@ import $ from 'jquery'; import React, { RefObject } from 'react'; -import { METRIC_TYPE } from '@kbn/analytics'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import type { PersistedState } from '@kbn/visualizations-plugin/public'; import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/public'; -import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; -import { getUsageCollectionStart } from './services'; import { VisTypeVislibCoreSetup } from './plugin'; import { VisLegend, CUSTOM_LEGEND_VIS_TYPES } from './vislib/components/legend'; import { BasicVislibParams } from './types'; @@ -30,38 +27,6 @@ const legendClassName = { export type VislibVisController = InstanceType>; -/** @internal **/ -const extractContainerType = (context?: KibanaExecutionContext): string | undefined => { - if (context) { - const recursiveGet = (item: KibanaExecutionContext): KibanaExecutionContext | undefined => { - if (item.type) { - return item; - } else if (item.child) { - return recursiveGet(item.child); - } - }; - return recursiveGet(context)?.type; - } -}; - -const renderComplete = ( - visParams: BasicVislibParams | PieVisParams, - handlers: IInterpreterRenderHandlers -) => { - const usageCollection = getUsageCollectionStart(); - const containerType = extractContainerType(handlers.getExecutionContext()); - - if (usageCollection && containerType) { - usageCollection.reportUiCounter( - containerType, - METRIC_TYPE.COUNT, - `render_agg_based_${visParams.type}` - ); - } - - handlers.done(); -}; - export const createVislibVisController = ( core: VisTypeVislibCoreSetup, charts: ChartsPluginSetup @@ -99,7 +64,8 @@ export const createVislibVisController = ( async render( esResponse: any, visParams: BasicVislibParams | PieVisParams, - handlers: IInterpreterRenderHandlers + handlers: IInterpreterRenderHandlers, + renderComplete: (() => void) | undefined ): Promise { if (this.vislibVis) { this.destroy(false); @@ -109,7 +75,7 @@ export const createVislibVisController = ( this.chartEl.dataset.vislibChartType = visParams.type; if (this.el.clientWidth === 0 || this.el.clientHeight === 0) { - renderComplete(visParams, handlers); + renderComplete?.(); return; } @@ -133,7 +99,7 @@ export const createVislibVisController = ( this.mountLegend(esResponse, visParams, fireEvent, uiState as PersistedState); } - renderComplete(visParams, handlers); + renderComplete?.(); }); this.removeListeners = () => { diff --git a/src/plugins/vis_types/vislib/public/vis_wrapper.tsx b/src/plugins/vis_types/vislib/public/vis_wrapper.tsx index a800abd3d11fb..5a68e74b5a485 100644 --- a/src/plugins/vis_types/vislib/public/vis_wrapper.tsx +++ b/src/plugins/vis_types/vislib/public/vis_wrapper.tsx @@ -6,20 +6,23 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo, useRef } from 'react'; -import { EuiResizeObserver } from '@elastic/eui'; +import React, { useEffect, useMemo, useRef, useCallback } from 'react'; +import { EuiResizeObserver, EuiResizeObserverProps } from '@elastic/eui'; import { debounce } from 'lodash'; import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/public'; import type { PersistedState } from '@kbn/visualizations-plugin/public'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; +import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import { METRIC_TYPE } from '@kbn/analytics'; import { VislibRenderValue } from './vis_type_vislib_vis_fn'; import { createVislibVisController, VislibVisController } from './vis_controller'; import { VisTypeVislibCoreSetup } from './plugin'; import { PieRenderValue } from './pie_fn'; import './index.scss'; +import { getUsageCollectionStart } from './services'; type VislibWrapperProps = (VislibRenderValue | PieRenderValue) & { core: VisTypeVislibCoreSetup; @@ -27,20 +30,67 @@ type VislibWrapperProps = (VislibRenderValue | PieRenderValue) & { handlers: IInterpreterRenderHandlers; }; +/** @internal **/ +const extractContainerType = (context?: KibanaExecutionContext): string | undefined => { + if (context) { + const recursiveGet = (item: KibanaExecutionContext): KibanaExecutionContext | undefined => { + if (item.type) { + return item; + } else if (item.child) { + return recursiveGet(item.child); + } + }; + return recursiveGet(context)?.type; + } +}; + const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWrapperProps) => { const chartDiv = useRef(null); const visController = useRef(null); + const skipRenderComplete = useRef(true); + + const renderComplete = useMemo( + () => () => { + const usageCollection = getUsageCollectionStart(); + const containerType = extractContainerType(handlers.getExecutionContext()); + + if (usageCollection && containerType) { + usageCollection.reportUiCounter( + containerType, + METRIC_TYPE.COUNT, + `render_agg_based_${visConfig!.type}` + ); + } + handlers.done(); + }, + [handlers, visConfig] + ); - const updateChart = useMemo( + const renderChart = useMemo( () => debounce(() => { if (visController.current) { - visController.current.render(visData, visConfig, handlers); + visController.current.render( + visData, + visConfig, + handlers, + skipRenderComplete.current ? undefined : renderComplete + ); } + skipRenderComplete.current = true; }, 100), - [visConfig, visData, handlers] + [handlers, renderComplete, skipRenderComplete, visConfig, visData] ); + const onResize: EuiResizeObserverProps['onResize'] = useCallback(() => { + renderChart(); + }, [renderChart]); + + useEffect(() => { + skipRenderComplete.current = false; + renderChart(); + }, [renderChart]); + useEffect(() => { if (chartDiv.current) { const Controller = createVislibVisController(core, charts); @@ -52,22 +102,20 @@ const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWra }; }, [core, charts]); - useEffect(updateChart, [updateChart]); - useEffect(() => { if (handlers.uiState) { const uiState = handlers.uiState as PersistedState; - uiState.on('change', updateChart); + uiState.on('change', renderChart); return () => { - uiState?.off('change', updateChart); + uiState?.off('change', renderChart); }; } - }, [handlers.uiState, updateChart]); + }, [handlers.uiState, renderChart]); return ( - + {(resizeRef) => (
diff --git a/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts b/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts index 4f7a5ad715215..f62f61f0c50ab 100644 --- a/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts +++ b/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts @@ -183,6 +183,7 @@ export interface ColumnState { summaryRow?: 'none' | 'sum' | 'avg' | 'count' | 'min' | 'max'; alignment?: 'left' | 'right' | 'center'; collapseFn?: CollapseFunction; + palette?: PaletteOutput; } export interface TableVisConfiguration { diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx index e7512c6dd6473..0111c9026397d 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx @@ -114,6 +114,7 @@ const TopNav = ({ vis.type, vis.params, uiStateJSON?.vis, + uiStateJSON?.table, vis.data.indexPattern, ]); diff --git a/test/analytics/tests/instrumented_events/from_the_browser/core_context_providers.ts b/test/analytics/tests/instrumented_events/from_the_browser/core_context_providers.ts index 3d0b018156ce7..79e43f0df086f 100644 --- a/test/analytics/tests/instrumented_events/from_the_browser/core_context_providers.ts +++ b/test/analytics/tests/instrumented_events/from_the_browser/core_context_providers.ts @@ -91,5 +91,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(event.context).not.to.have.property('cloudId'); } }); + + it('should have the properties provided by the "viewport_size" context provider', async () => { + expect(event.context).to.have.property('viewport_width'); + expect(event.context.viewport_width).to.be.a('number'); + expect(event.context).to.have.property('viewport_height'); + expect(event.context.viewport_height).to.be.a('number'); + }); }); } diff --git a/test/analytics/tests/instrumented_events/from_the_browser/index.ts b/test/analytics/tests/instrumented_events/from_the_browser/index.ts index 7c6ee6ff1e2af..c69f091cc4543 100644 --- a/test/analytics/tests/instrumented_events/from_the_browser/index.ts +++ b/test/analytics/tests/instrumented_events/from_the_browser/index.ts @@ -15,5 +15,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./loaded_kibana')); loadTestFile(require.resolve('./loaded_dashboard')); loadTestFile(require.resolve('./core_context_providers')); + loadTestFile(require.resolve('./viewport_resize')); }); } diff --git a/test/analytics/tests/instrumented_events/from_the_browser/viewport_resize.ts b/test/analytics/tests/instrumented_events/from_the_browser/viewport_resize.ts new file mode 100644 index 0000000000000..f5e084810a375 --- /dev/null +++ b/test/analytics/tests/instrumented_events/from_the_browser/viewport_resize.ts @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../services'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const ebtUIHelper = getService('kibana_ebt_ui'); + const browser = getService('browser'); + const { common } = getPageObjects(['common']); + + describe('Event "viewport_resize"', () => { + beforeEach(async () => { + // Navigating to `home` with the Welcome prompt because some runs were flaky + // as we handle the Welcome screen only if the login prompt pops up. + // Otherwise, it stays in the Welcome screen :/ + await common.navigateToApp('home'); + }); + + it('should emit a "viewport_resize" event when the browser is resized', async () => { + const events = await ebtUIHelper.getEvents(1, { + eventTypes: ['viewport_resize'], + withTimeoutMs: 100, + }); + expect(events.length).to.be(0); + // Resize the window + await browser.setWindowSize(500, 500); + const { height, width } = await browser.getWindowSize(); + expect(height).to.eql(500); + expect(width).to.eql(500); + + const actualInnerHeight = await browser.execute(() => window.innerHeight); + expect(actualInnerHeight <= height).to.be(true); // The address bar takes some space when not running on HEADLESS + + const [event] = await ebtUIHelper.getEvents(1, { eventTypes: ['viewport_resize'] }); + expect(event.event_type).to.eql('viewport_resize'); + expect(event.properties).to.eql({ + viewport_width: 500, + viewport_height: actualInnerHeight, + }); + + // Validating that the context is also updated + expect(event.context.viewport_width).to.be(500); + expect(event.context.viewport_height).to.be(actualInnerHeight); + }); + }); +} diff --git a/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts b/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts index a27a1a4814cfb..89a435430f9e9 100644 --- a/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts +++ b/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts @@ -123,6 +123,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ]); }); + it('Excluding selections in the first control will validate the second and third controls', async () => { + await dashboardControls.optionsListOpenPopover(controlIds[0]); + await dashboardControls.optionsListPopoverSetIncludeSelections(false); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); + + await ensureAvailableOptionsEql(controlIds[1], ['Tiger', 'sylvester']); + await ensureAvailableOptionsEql(controlIds[2], ['meow', 'hiss']); + }); + + it('Excluding all options of first control removes all options in second and third controls', async () => { + await dashboardControls.optionsListOpenPopover(controlIds[0]); + await dashboardControls.optionsListPopoverSelectOption('cat'); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); + + await dashboardControls.optionsListOpenPopover(controlIds[1]); + expect(await dashboardControls.optionsListPopoverGetAvailableOptionsCount()).to.be(0); + await dashboardControls.optionsListOpenPopover(controlIds[2]); + expect(await dashboardControls.optionsListPopoverGetAvailableOptionsCount()).to.be(0); + await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[2]); + }); + describe('Hierarchical chaining off', async () => { before(async () => { await dashboardControls.updateChainingSystem('NONE'); @@ -130,6 +151,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('Selecting an option in the first Options List will not filter the second or third controls', async () => { await dashboardControls.optionsListOpenPopover(controlIds[0]); + await dashboardControls.optionsListPopoverSetIncludeSelections(true); await dashboardControls.optionsListPopoverSelectOption('cat'); await dashboardControls.optionsListEnsurePopoverIsClosed(controlIds[0]); diff --git a/test/functional/apps/dashboard_elements/controls/options_list.ts b/test/functional/apps/dashboard_elements/controls/options_list.ts index 0c8dea528d9e4..091f893eec2cf 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list.ts @@ -385,6 +385,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await pieChart.getPieSliceCount()).to.be(2); }); + it('excluding selections has expected results', async () => { + await dashboard.clickQuickSave(); + await dashboard.waitForRenderComplete(); + + await dashboardControls.optionsListOpenPopover(controlId); + await dashboardControls.optionsListPopoverSetIncludeSelections(false); + await dashboard.waitForRenderComplete(); + + expect(await pieChart.getPieSliceCount()).to.be(5); + await dashboard.clearUnsavedChanges(); + }); + + it('including selections has expected results', async () => { + await dashboardControls.optionsListOpenPopover(controlId); + await dashboardControls.optionsListPopoverSetIncludeSelections(true); + await dashboard.waitForRenderComplete(); + + expect(await pieChart.getPieSliceCount()).to.be(2); + await dashboard.clearUnsavedChanges(); + }); + it('Can mark multiple selections invalid with Filter', async () => { await filterBar.addFilter('sound.keyword', 'is', ['hiss']); await dashboard.waitForRenderComplete(); diff --git a/test/functional/apps/discover/group1/_discover.ts b/test/functional/apps/discover/group1/_discover.ts index 4b5137fadeb5c..60f2a54dd01fd 100644 --- a/test/functional/apps/discover/group1/_discover.ts +++ b/test/functional/apps/discover/group1/_discover.ts @@ -26,8 +26,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }; - // FLAKY: https://github.com/elastic/kibana/issues/142222 - describe.skip('discover test', function describeIndexTests() { + describe('discover test', function describeIndexTests() { before(async function () { log.debug('load kibana index with default index pattern'); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); @@ -370,14 +369,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.header.waitUntilLoadingHasFinished(); const dataViewId = await PageObjects.discover.getCurrentDataViewId(); - const originalUrl = await browser.getCurrentUrl(); const newUrl = originalUrl.replace(dataViewId, 'invalid-data-view-id'); await browser.get(newUrl); - await PageObjects.header.waitUntilLoadingHasFinished(); - expect(await browser.getCurrentUrl()).to.be(originalUrl); - expect(await testSubjects.exists('dscDataViewNotFoundShowDefaultWarning')).to.be(true); + await retry.try(async () => { + expect(await browser.getCurrentUrl()).to.be(originalUrl); + expect(await testSubjects.exists('dscDataViewNotFoundShowDefaultWarning')).to.be(true); + }); }); it('should show a warning and fall back to the current data view if the URL is updated to an invalid data view ID', async () => { @@ -385,14 +384,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); const originalHash = await browser.execute<[], string>('return window.location.hash'); const dataViewId = await PageObjects.discover.getCurrentDataViewId(); - const newHash = originalHash.replace(dataViewId, 'invalid-data-view-id'); await browser.execute(`window.location.hash = "${newHash}"`); await PageObjects.header.waitUntilLoadingHasFinished(); - - const currentHash = await browser.execute<[], string>('return window.location.hash'); - expect(currentHash).to.be(originalHash); - expect(await testSubjects.exists('dscDataViewNotFoundShowSavedWarning')).to.be(true); + await retry.try(async () => { + const currentHash = await browser.execute<[], string>('return window.location.hash'); + expect(currentHash).to.be(originalHash); + expect(await testSubjects.exists('dscDataViewNotFoundShowSavedWarning')).to.be(true); + }); }); }); }); diff --git a/test/functional/apps/management/_index_pattern_filter.ts b/test/functional/apps/management/_index_pattern_filter.ts index afa64c474d39d..e1e39e93cc6c5 100644 --- a/test/functional/apps/management/_index_pattern_filter.ts +++ b/test/functional/apps/management/_index_pattern_filter.ts @@ -15,7 +15,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['settings']); const esArchiver = getService('esArchiver'); - describe('index pattern filter', function describeIndexTests() { + // Failing: See https://github.com/elastic/kibana/issues/143109 + describe.skip('index pattern filter', function describeIndexTests() { before(async function () { await esArchiver.emptyKibanaIndex(); await kibanaServer.uiSettings.replace({}); diff --git a/test/functional/page_objects/dashboard_page_controls.ts b/test/functional/page_objects/dashboard_page_controls.ts index 15510a07dccb0..1e04ebb467d89 100644 --- a/test/functional/page_objects/dashboard_page_controls.ts +++ b/test/functional/page_objects/dashboard_page_controls.ts @@ -376,6 +376,19 @@ export class DashboardPageControls extends FtrService { await this.testSubjects.click(`optionsList-control-clear-all-selections`); } + public async optionsListPopoverSetIncludeSelections(include: boolean) { + this.log.debug(`exclude selections`); + await this.optionsListPopoverAssertOpen(); + + const buttonGroup = await this.testSubjects.find('optionsList__includeExcludeButtonGroup'); + await ( + await this.find.descendantDisplayedByCssSelector( + include ? '[data-text="Include"]' : '[data-text="Exclude"]', + buttonGroup + ) + ).click(); + } + /* ----------------------------------------------------------- Control editor flyout ----------------------------------------------------------- */ diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 85c93c0fc2847..44a29441d2707 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -243,6 +243,10 @@ export class DiscoverPageObject extends FtrService { return await this.testSubjects.getVisibleText('unifiedHistogramQueryHits'); } + public async getHitCountInt() { + return parseInt(await this.getHitCount(), 10); + } + public async getDocHeader() { const table = await this.getDocTable(); const docHeader = await table.getHeaders(); diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index edbd53e80d8c5..1aacde4127f37 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -659,6 +659,28 @@ export class VisualBuilderPageObject extends FtrService { await this.comboBox.setElement(fieldEl, field); } + public async setFieldForAggregateBy(field: string): Promise { + const aggregateBy = await this.testSubjects.find('tsvbAggregateBySelect'); + + await this.retry.try(async () => { + await this.comboBox.setElement(aggregateBy, field); + if (!(await this.comboBox.isOptionSelected(aggregateBy, field))) { + throw new Error(`aggregate by field - ${field} is not selected`); + } + }); + } + + public async setFunctionForAggregateFunction(func: string): Promise { + const aggregateFunction = await this.testSubjects.find('tsvbAggregateFunctionCombobox'); + + await this.retry.try(async () => { + await this.comboBox.setElement(aggregateFunction, func); + if (!(await this.comboBox.isOptionSelected(aggregateFunction, func))) { + throw new Error(`aggregate function - ${func} is not selected`); + } + }); + } + public async checkFieldForAggregationValidity(aggNth: number = 0): Promise { const fieldEl = await this.getFieldForAggregation(aggNth); diff --git a/versions.json b/versions.json index 30514180e5c1e..3265499716cd1 100644 --- a/versions.json +++ b/versions.json @@ -20,7 +20,7 @@ "previousMinor": true }, { - "version": "7.17.7", + "version": "7.17.8", "branch": "7.17", "previousMajor": true } diff --git a/x-pack/examples/files_example/public/components/app.tsx b/x-pack/examples/files_example/public/components/app.tsx index d3dfbdeb71874..afdf8be1f4f6e 100644 --- a/x-pack/examples/files_example/public/components/app.tsx +++ b/x-pack/examples/files_example/public/components/app.tsx @@ -36,8 +36,10 @@ interface FilesExampleAppDeps { type ListResponse = FilesClientResponses['list']; export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) => { - const { data, isLoading, error, refetch } = useQuery(['files'], () => - files.example.list() + const { data, isLoading, error, refetch } = useQuery( + ['files'], + () => files.example.list(), + { refetchOnWindowFocus: false } ); const [showUploadModal, setShowUploadModal] = useState(false); const [showFilePickerModal, setShowFilePickerModal] = useState(false); diff --git a/x-pack/examples/files_example/public/components/file_picker.tsx b/x-pack/examples/files_example/public/components/file_picker.tsx index 2bf5530655ba3..3c2178b299ea2 100644 --- a/x-pack/examples/files_example/public/components/file_picker.tsx +++ b/x-pack/examples/files_example/public/components/file_picker.tsx @@ -18,5 +18,5 @@ interface Props { } export const MyFilePicker: FunctionComponent = ({ onClose, onDone }) => { - return ; + return ; }; diff --git a/x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts b/x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts index 338f55ad754c2..7986747d34dd3 100644 --- a/x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts +++ b/x-pack/packages/ml/agg_utils/src/fetch_agg_intervals.ts @@ -29,7 +29,8 @@ export const fetchAggIntervals = async ( query: estypes.QueryDslQueryContainer, fields: HistogramField[], samplerShardSize: number, - runtimeMappings?: estypes.MappingRuntimeFields + runtimeMappings?: estypes.MappingRuntimeFields, + abortSignal?: AbortSignal ): Promise => { const numericColumns = fields.filter((field) => { return field.type === KBN_FIELD_TYPES.NUMBER || field.type === KBN_FIELD_TYPES.DATE; @@ -49,16 +50,19 @@ export const fetchAggIntervals = async ( return aggs; }, {} as Record); - const body = await client.search({ - index: indexPattern, - size: 0, - body: { - query, - aggs: buildSamplerAggregation(minMaxAggs, samplerShardSize), + const body = await client.search( + { + index: indexPattern, size: 0, - ...(isPopulatedObject(runtimeMappings) ? { runtime_mappings: runtimeMappings } : {}), + body: { + query, + aggs: buildSamplerAggregation(minMaxAggs, samplerShardSize), + size: 0, + ...(isPopulatedObject(runtimeMappings) ? { runtime_mappings: runtimeMappings } : {}), + }, }, - }); + { signal: abortSignal, maxRetries: 0 } + ); const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize); const aggregations = aggsPath.length > 0 ? get(body.aggregations, aggsPath) : body.aggregations; diff --git a/x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts b/x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts index a921eaeae370b..70d5f6360155d 100644 --- a/x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts +++ b/x-pack/packages/ml/agg_utils/src/fetch_histograms_for_fields.ts @@ -146,7 +146,8 @@ export const fetchHistogramsForFields = async ( query: any, fields: FieldsForHistograms, samplerShardSize: number, - runtimeMappings?: estypes.MappingRuntimeFields + runtimeMappings?: estypes.MappingRuntimeFields, + abortSignal?: AbortSignal ) => { const aggIntervals = { ...(await fetchAggIntervals( @@ -155,7 +156,8 @@ export const fetchHistogramsForFields = async ( query, fields.filter((f) => !isNumericHistogramFieldWithColumnStats(f)), samplerShardSize, - runtimeMappings + runtimeMappings, + abortSignal )), ...fields.filter(isNumericHistogramFieldWithColumnStats).reduce((p, field) => { const { interval, min, max, fieldName } = field; @@ -209,7 +211,7 @@ export const fetchHistogramsForFields = async ( ...(isPopulatedObject(runtimeMappings) ? { runtime_mappings: runtimeMappings } : {}), }, }, - { maxRetries: 0 } + { signal: abortSignal, maxRetries: 0 } ); const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize); diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index 8f4c4eee61e84..19447bf8e79e5 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -16,7 +16,6 @@ import { import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from './constants/saved_objects'; import { ExecuteOptions as ActionExecutorOptions } from './lib/action_executor'; import { extractSavedObjectReferences, isSavedObjectExecutionSource } from './lib'; -import { RelatedSavedObjects } from './lib/related_saved_objects'; interface CreateExecuteFunctionOptions { taskManager: TaskManagerStartContract; @@ -25,21 +24,18 @@ interface CreateExecuteFunctionOptions { preconfiguredActions: PreConfiguredAction[]; } -export interface ExecuteOptions extends Pick { +export interface ExecuteOptions + extends Pick { id: string; spaceId: string; apiKey: string | null; executionId: string; - consumer?: string; - relatedSavedObjects?: RelatedSavedObjects; } -export interface ActionTaskParams extends Pick { - actionId: string; +interface ActionTaskParams + extends Pick { apiKey: string | null; executionId: string; - consumer?: string; - relatedSavedObjects?: RelatedSavedObjects; } export interface GetConnectorsResult { @@ -176,43 +172,40 @@ export function createBulkExecutionEnqueuerFunction({ connectorIsPreconfigured[id] = isPreconfigured; }); - const actions = await Promise.all( - actionsToExecute.map(async (actionToExecute) => { - // Get saved object references from action ID and relatedSavedObjects - const { references, relatedSavedObjectWithRefs } = extractSavedObjectReferences( - actionToExecute.id, - connectorIsPreconfigured[actionToExecute.id], - actionToExecute.relatedSavedObjects - ); - const executionSourceReference = executionSourceAsSavedObjectReferences( - actionToExecute.source - ); - - const taskReferences = []; - if (executionSourceReference.references) { - taskReferences.push(...executionSourceReference.references); - } - if (references) { - taskReferences.push(...references); - } - - spaceIds[actionToExecute.id] = actionToExecute.spaceId; - - return { - type: ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - attributes: { - actionId: actionToExecute.id, - params: actionToExecute.params, - apiKey: actionToExecute.apiKey, - executionId: actionToExecute.executionId, - consumer: actionToExecute.consumer, - relatedSavedObjects: relatedSavedObjectWithRefs, - }, - references: taskReferences, - }; - }) - ); + const actions = actionsToExecute.map((actionToExecute) => { + // Get saved object references from action ID and relatedSavedObjects + const { references, relatedSavedObjectWithRefs } = extractSavedObjectReferences( + actionToExecute.id, + connectorIsPreconfigured[actionToExecute.id], + actionToExecute.relatedSavedObjects + ); + const executionSourceReference = executionSourceAsSavedObjectReferences( + actionToExecute.source + ); + + const taskReferences = []; + if (executionSourceReference.references) { + taskReferences.push(...executionSourceReference.references); + } + if (references) { + taskReferences.push(...references); + } + spaceIds[actionToExecute.id] = actionToExecute.spaceId; + + return { + type: ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + attributes: { + actionId: actionToExecute.id, + params: actionToExecute.params, + apiKey: actionToExecute.apiKey, + executionId: actionToExecute.executionId, + consumer: actionToExecute.consumer, + relatedSavedObjects: relatedSavedObjectWithRefs, + }, + references: taskReferences, + }; + }); const actionTaskParamsRecords: SavedObjectsBulkResponse = await unsecuredSavedObjectsClient.bulkCreate(actions); const taskInstances = actionTaskParamsRecords.saved_objects.map((so) => { diff --git a/x-pack/plugins/actions/server/create_unsecured_execute_function.test.ts b/x-pack/plugins/actions/server/create_unsecured_execute_function.test.ts new file mode 100644 index 0000000000000..ea8407b956276 --- /dev/null +++ b/x-pack/plugins/actions/server/create_unsecured_execute_function.test.ts @@ -0,0 +1,481 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import uuid from 'uuid'; +import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { createBulkUnsecuredExecutionEnqueuerFunction } from './create_unsecured_execute_function'; +import { actionTypeRegistryMock } from './action_type_registry.mock'; +import { asSavedObjectExecutionSource } from './lib/action_execution_source'; + +const mockTaskManager = taskManagerMock.createStart(); +const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); + +beforeEach(() => jest.resetAllMocks()); + +describe('bulkExecute()', () => { + test('schedules the actions with all given parameters with a preconfigured connector', async () => { + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: actionTypeRegistryMock.create(), + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + + internalSavedObjectsRepository.bulkCreate.mockResolvedValueOnce({ + saved_objects: [ + { + id: '234', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [], + }, + { + id: '345', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [], + }, + ], + }); + await executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + }, + { + id: '123', + params: { baz: true }, + }, + ]); + expect(mockTaskManager.bulkSchedule).toHaveBeenCalledTimes(1); + expect(mockTaskManager.bulkSchedule.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "params": Object { + "actionTaskParamsId": "234", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + Object { + "params": Object { + "actionTaskParamsId": "345", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + ], + ] + `); + + expect(internalSavedObjectsRepository.bulkCreate).toHaveBeenCalledWith([ + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: false }, + apiKey: null, + }, + references: [], + }, + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: true }, + apiKey: null, + }, + references: [], + }, + ]); + }); + + test('schedules the actions with all given parameters with a preconfigured connector and source specified', async () => { + const sourceUuid = uuid.v4(); + const source = { type: 'alert', id: sourceUuid }; + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: actionTypeRegistryMock.create(), + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + + internalSavedObjectsRepository.bulkCreate.mockResolvedValueOnce({ + saved_objects: [ + { + id: '234', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [ + { + id: sourceUuid, + name: 'source', + type: 'alert', + }, + ], + }, + { + id: '345', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [], + }, + ], + }); + await executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + source: asSavedObjectExecutionSource(source), + }, + { + id: '123', + params: { baz: true }, + }, + ]); + expect(mockTaskManager.bulkSchedule).toHaveBeenCalledTimes(1); + expect(mockTaskManager.bulkSchedule.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "params": Object { + "actionTaskParamsId": "234", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + Object { + "params": Object { + "actionTaskParamsId": "345", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + ], + ] + `); + + expect(internalSavedObjectsRepository.bulkCreate).toHaveBeenCalledWith([ + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: false }, + apiKey: null, + }, + references: [ + { + id: sourceUuid, + name: 'source', + type: 'alert', + }, + ], + }, + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: true }, + apiKey: null, + }, + references: [], + }, + ]); + }); + + test('schedules the actions with all given parameters with a preconfigured connector and relatedSavedObjects specified', async () => { + const sourceUuid = uuid.v4(); + const source = { type: 'alert', id: sourceUuid }; + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: actionTypeRegistryMock.create(), + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + + internalSavedObjectsRepository.bulkCreate.mockResolvedValueOnce({ + saved_objects: [ + { + id: '234', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [ + { + id: sourceUuid, + name: 'source', + type: 'alert', + }, + ], + }, + { + id: '345', + type: 'action_task_params', + attributes: { + actionId: '123', + }, + references: [ + { + id: 'some-id', + name: 'related_some-type_0', + type: 'some-type', + }, + ], + }, + ], + }); + await executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + source: asSavedObjectExecutionSource(source), + }, + { + id: '123', + params: { baz: true }, + relatedSavedObjects: [ + { + id: 'some-id', + namespace: 'some-namespace', + type: 'some-type', + }, + ], + }, + ]); + expect(mockTaskManager.bulkSchedule).toHaveBeenCalledTimes(1); + expect(mockTaskManager.bulkSchedule.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "params": Object { + "actionTaskParamsId": "234", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + Object { + "params": Object { + "actionTaskParamsId": "345", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:.email", + }, + ], + ] + `); + + expect(internalSavedObjectsRepository.bulkCreate).toHaveBeenCalledWith([ + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: false }, + apiKey: null, + }, + references: [ + { + id: sourceUuid, + name: 'source', + type: 'alert', + }, + ], + }, + { + type: 'action_task_params', + attributes: { + actionId: '123', + params: { baz: true }, + apiKey: null, + relatedSavedObjects: [ + { + id: 'related_some-type_0', + namespace: 'some-namespace', + type: 'some-type', + }, + ], + }, + references: [ + { + id: 'some-id', + name: 'related_some-type_0', + type: 'some-type', + }, + ], + }, + ]); + }); + + test('throws when scheduling action using non preconfigured connector', async () => { + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: actionTypeRegistryMock.create(), + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + await expect( + executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + }, + { + id: 'not-preconfigured', + params: { baz: true }, + }, + ]) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"not-preconfigured are not preconfigured connectors and can't be scheduled for unsecured actions execution"` + ); + }); + + test('throws when connector type is not enabled', async () => { + const mockedConnectorTypeRegistry = actionTypeRegistryMock.create(); + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: mockedConnectorTypeRegistry, + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + mockedConnectorTypeRegistry.ensureActionTypeEnabled.mockImplementation(() => { + throw new Error('Fail'); + }); + + await expect( + executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + }, + { + id: '123', + params: { baz: true }, + }, + ]) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Fail"`); + }); + + test('throws when scheduling action using non allow-listed preconfigured connector', async () => { + const executeFn = createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + connectorTypeRegistry: actionTypeRegistryMock.create(), + preconfiguredConnectors: [ + { + id: '123', + actionTypeId: '.email', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + { + id: '456', + actionTypeId: 'not-in-allowlist', + config: {}, + isPreconfigured: true, + isDeprecated: false, + name: 'x', + secrets: {}, + }, + ], + }); + await expect( + executeFn(internalSavedObjectsRepository, [ + { + id: '123', + params: { baz: false }, + }, + { + id: '456', + params: { baz: true }, + }, + ]) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"not-in-allowlist actions cannot be scheduled for unsecured actions execution"` + ); + }); +}); diff --git a/x-pack/plugins/actions/server/create_unsecured_execute_function.ts b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts new file mode 100644 index 0000000000000..4670601ecff83 --- /dev/null +++ b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ISavedObjectsRepository, SavedObjectsBulkResponse } from '@kbn/core/server'; +import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; +import { + ActionTypeRegistryContract as ConnectorTypeRegistryContract, + PreConfiguredAction as PreconfiguredConnector, +} from './types'; +import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from './constants/saved_objects'; +import { ExecuteOptions as ActionExecutorOptions } from './lib/action_executor'; +import { extractSavedObjectReferences, isSavedObjectExecutionSource } from './lib'; + +// This allowlist should only contain connector types that don't require API keys for +// execution. +const ALLOWED_CONNECTOR_TYPE_IDS = ['.email']; +interface CreateBulkUnsecuredExecuteFunctionOptions { + taskManager: TaskManagerStartContract; + connectorTypeRegistry: ConnectorTypeRegistryContract; + preconfiguredConnectors: PreconfiguredConnector[]; +} + +export interface ExecuteOptions + extends Pick { + id: string; +} + +interface ActionTaskParams + extends Pick { + apiKey: string | null; +} + +export type BulkUnsecuredExecutionEnqueuer = ( + internalSavedObjectsRepository: ISavedObjectsRepository, + actionsToExectute: ExecuteOptions[] +) => Promise; + +export function createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager, + connectorTypeRegistry, + preconfiguredConnectors, +}: CreateBulkUnsecuredExecuteFunctionOptions): BulkUnsecuredExecutionEnqueuer { + return async function execute( + internalSavedObjectsRepository: ISavedObjectsRepository, + actionsToExecute: ExecuteOptions[] + ) { + const connectorTypeIds: Record = {}; + const connectorIds = [...new Set(actionsToExecute.map((action) => action.id))]; + + const notPreconfiguredConnectors = connectorIds.filter( + (connectorId) => + preconfiguredConnectors.find((connector) => connector.id === connectorId) == null + ); + + if (notPreconfiguredConnectors.length > 0) { + throw new Error( + `${notPreconfiguredConnectors.join( + ',' + )} are not preconfigured connectors and can't be scheduled for unsecured actions execution` + ); + } + + const connectors: PreconfiguredConnector[] = connectorIds + .map((connectorId) => + preconfiguredConnectors.find((pConnector) => pConnector.id === connectorId) + ) + .filter(Boolean) as PreconfiguredConnector[]; + + connectors.forEach((connector) => { + const { id, actionTypeId } = connector; + if (!connectorTypeRegistry.isActionExecutable(id, actionTypeId, { notifyUsage: true })) { + connectorTypeRegistry.ensureActionTypeEnabled(actionTypeId); + } + + if (!ALLOWED_CONNECTOR_TYPE_IDS.includes(actionTypeId)) { + throw new Error( + `${actionTypeId} actions cannot be scheduled for unsecured actions execution` + ); + } + + connectorTypeIds[id] = actionTypeId; + }); + + const actions = actionsToExecute.map((actionToExecute) => { + // Get saved object references from action ID and relatedSavedObjects + const { references, relatedSavedObjectWithRefs } = extractSavedObjectReferences( + actionToExecute.id, + true, + actionToExecute.relatedSavedObjects + ); + const executionSourceReference = executionSourceAsSavedObjectReferences( + actionToExecute.source + ); + + const taskReferences = []; + if (executionSourceReference.references) { + taskReferences.push(...executionSourceReference.references); + } + if (references) { + taskReferences.push(...references); + } + + return { + type: ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + attributes: { + actionId: actionToExecute.id, + params: actionToExecute.params, + apiKey: null, + relatedSavedObjects: relatedSavedObjectWithRefs, + }, + references: taskReferences, + }; + }); + const actionTaskParamsRecords: SavedObjectsBulkResponse = + await internalSavedObjectsRepository.bulkCreate(actions); + + const taskInstances = actionTaskParamsRecords.saved_objects.map((so) => { + const actionId = so.attributes.actionId; + return { + taskType: `actions:${connectorTypeIds[actionId]}`, + params: { + spaceId: 'default', + actionTaskParamsId: so.id, + }, + state: {}, + scope: ['actions'], + }; + }); + await taskManager.bulkSchedule(taskInstances); + }; +} + +function executionSourceAsSavedObjectReferences(executionSource: ActionExecutorOptions['source']) { + return isSavedObjectExecutionSource(executionSource) + ? { + references: [ + { + name: 'source', + ...executionSource.source, + }, + ], + } + : {}; +} diff --git a/x-pack/plugins/actions/server/index.ts b/x-pack/plugins/actions/server/index.ts index 1c7a66978ffb3..2713ee17463e4 100644 --- a/x-pack/plugins/actions/server/index.ts +++ b/x-pack/plugins/actions/server/index.ts @@ -12,6 +12,8 @@ import { configSchema, ActionsConfig, CustomHostSettings } from './config'; import { ActionsClient as ActionsClientClass } from './actions_client'; import { ActionsAuthorization as ActionsAuthorizationClass } from './authorization/actions_authorization'; +export type { IUnsecuredActionsClient } from './unsecured_actions_client/unsecured_actions_client'; +export { UnsecuredActionsClient } from './unsecured_actions_client/unsecured_actions_client'; export type ActionsClient = PublicMethodsOf; export type ActionsAuthorization = PublicMethodsOf; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 849cd2ff44ba5..4fde645fb367e 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -47,7 +47,21 @@ actionExecutor.initialize({ actionTypeRegistry, encryptedSavedObjectsClient, eventLogger, - preconfiguredActions: [], + preconfiguredActions: [ + { + id: 'preconfigured', + name: 'Preconfigured', + actionTypeId: 'test', + config: { + bar: 'preconfigured', + }, + secrets: { + apiKey: 'abc', + }, + isPreconfigured: true, + isDeprecated: false, + }, + ], }); beforeEach(() => { @@ -183,6 +197,107 @@ test('successfully executes', async () => { `); }); +test('successfully executes with preconfigured connector', async () => { + const actionType: jest.Mocked = { + id: 'test', + name: 'Test', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + executor: jest.fn(), + }; + + actionTypeRegistry.get.mockReturnValueOnce(actionType); + await actionExecutor.execute({ ...executeParams, actionId: 'preconfigured' }); + + expect(actionsClient.get).not.toHaveBeenCalled(); + expect(encryptedSavedObjectsClient.getDecryptedAsInternalUser).not.toHaveBeenCalled(); + + expect(actionTypeRegistry.get).toHaveBeenCalledWith('test'); + expect(actionTypeRegistry.isActionExecutable).toHaveBeenCalledWith('preconfigured', 'test', { + notifyUsage: true, + }); + + expect(actionType.executor).toHaveBeenCalledWith({ + actionId: 'preconfigured', + services: expect.anything(), + config: { + bar: 'preconfigured', + }, + secrets: { + apiKey: 'abc', + }, + params: { foo: true }, + logger: loggerMock, + }); + + expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); + expect(eventLogger.logEvent.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "event": Object { + "action": "execute-start", + "kind": "action", + }, + "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, + "saved_objects": Array [ + Object { + "id": "preconfigured", + "namespace": "some-namespace", + "rel": "primary", + "type": "action", + "type_id": "test", + }, + ], + "space_ids": Array [ + "some-namespace", + ], + }, + "message": "action started: test:preconfigured: Preconfigured", + }, + ], + Array [ + Object { + "event": Object { + "action": "execute", + "kind": "action", + "outcome": "success", + }, + "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, + "saved_objects": Array [ + Object { + "id": "preconfigured", + "namespace": "some-namespace", + "rel": "primary", + "type": "action", + "type_id": "test", + }, + ], + "space_ids": Array [ + "some-namespace", + ], + }, + "message": "action executed: test:preconfigured: Preconfigured", + }, + ], + ] + `); +}); + test('successfully executes as a task', async () => { const actionType: jest.Mocked = { id: 'test', @@ -509,6 +624,132 @@ test('throws an error when passing isESOCanEncrypt with value of false', async ( ); }); +test('should not throw error if action is preconfigured and isESOCanEncrypt is false', async () => { + const customActionExecutor = new ActionExecutor({ isESOCanEncrypt: false }); + customActionExecutor.initialize({ + logger: loggingSystemMock.create().get(), + spaces: spacesMock, + getActionsClientWithRequest, + getServices: () => services, + actionTypeRegistry, + encryptedSavedObjectsClient, + eventLogger: eventLoggerMock.create(), + preconfiguredActions: [ + { + id: 'preconfigured', + name: 'Preconfigured', + actionTypeId: 'test', + config: { + bar: 'preconfigured', + }, + secrets: { + apiKey: 'abc', + }, + isPreconfigured: true, + isDeprecated: false, + }, + ], + }); + const actionType: jest.Mocked = { + id: 'test', + name: 'Test', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + executor: jest.fn(), + }; + + actionTypeRegistry.get.mockReturnValueOnce(actionType); + await actionExecutor.execute({ ...executeParams, actionId: 'preconfigured' }); + + expect(actionsClient.get).not.toHaveBeenCalled(); + expect(encryptedSavedObjectsClient.getDecryptedAsInternalUser).not.toHaveBeenCalled(); + + expect(actionTypeRegistry.get).toHaveBeenCalledWith('test'); + expect(actionTypeRegistry.isActionExecutable).toHaveBeenCalledWith('preconfigured', 'test', { + notifyUsage: true, + }); + + expect(actionType.executor).toHaveBeenCalledWith({ + actionId: 'preconfigured', + services: expect.anything(), + config: { + bar: 'preconfigured', + }, + secrets: { + apiKey: 'abc', + }, + params: { foo: true }, + logger: loggerMock, + }); + + expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); + expect(eventLogger.logEvent.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "event": Object { + "action": "execute-start", + "kind": "action", + }, + "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, + "saved_objects": Array [ + Object { + "id": "preconfigured", + "namespace": "some-namespace", + "rel": "primary", + "type": "action", + "type_id": "test", + }, + ], + "space_ids": Array [ + "some-namespace", + ], + }, + "message": "action started: test:preconfigured: Preconfigured", + }, + ], + Array [ + Object { + "event": Object { + "action": "execute", + "kind": "action", + "outcome": "success", + }, + "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, + "saved_objects": Array [ + Object { + "id": "preconfigured", + "namespace": "some-namespace", + "rel": "primary", + "type": "action", + "type_id": "test", + }, + ], + "space_ids": Array [ + "some-namespace", + ], + }, + "message": "action executed: test:preconfigured: Preconfigured", + }, + ], + ] + `); +}); + test('does not log warning when alert executor succeeds', async () => { const executorMock = setupActionExecutorMock(); executorMock.mockResolvedValue({ diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 90603499cd4a7..42e5c8c8e1a99 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -105,12 +105,6 @@ export class ActionExecutor { throw new Error('ActionExecutor not initialized'); } - if (!this.isESOCanEncrypt) { - throw new Error( - `Unable to execute action because the Encrypted Saved Objects plugin is missing encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command.` - ); - } - return withSpan( { name: `execute_action`, @@ -135,11 +129,14 @@ export class ActionExecutor { const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; const actionInfo = await getActionInfoInternal( - await getActionsClientWithRequest(request, source), + getActionsClientWithRequest, + request, + this.isESOCanEncrypt, encryptedSavedObjectsClient, preconfiguredActions, actionId, - namespace.namespace + namespace.namespace, + source ); const { actionTypeId, name, config, secrets } = actionInfo; @@ -321,11 +318,14 @@ export class ActionExecutor { const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; if (!this.actionInfo || this.actionInfo.actionId !== actionId) { this.actionInfo = await getActionInfoInternal( - await getActionsClientWithRequest(request, source), + getActionsClientWithRequest, + request, + this.isESOCanEncrypt, encryptedSavedObjectsClient, preconfiguredActions, actionId, - namespace.namespace + namespace.namespace, + source ); } const task = taskInfo @@ -371,12 +371,18 @@ interface ActionInfo { actionId: string; } -async function getActionInfoInternal( - actionsClient: PublicMethodsOf, +async function getActionInfoInternal( + getActionsClientWithRequest: ( + request: KibanaRequest, + authorizationContext?: ActionExecutionSource + ) => Promise>, + request: KibanaRequest, + isESOCanEncrypt: boolean, encryptedSavedObjectsClient: EncryptedSavedObjectsClient, preconfiguredActions: PreConfiguredAction[], actionId: string, - namespace: string | undefined + namespace: string | undefined, + source?: ActionExecutionSource ): Promise { // check to see if it's a pre-configured action first const pcAction = preconfiguredActions.find( @@ -392,6 +398,14 @@ async function getActionInfoInternal( }; } + if (!isESOCanEncrypt) { + throw new Error( + `Unable to execute action because the Encrypted Saved Objects plugin is missing encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command.` + ); + } + + const actionsClient = await getActionsClientWithRequest(request, source); + // if not pre-configured action, should be a saved object // ensure user can read the action before processing const { actionTypeId, config, name } = await actionsClient.get({ id: actionId }); diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts index 72cbda1312b9a..69eca915cc721 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts @@ -109,6 +109,43 @@ describe('createActionEventLogRecordObject', () => { }); }); + test('created action event "execute" with no kibana.alert.rule fields', async () => { + expect( + createActionEventLogRecordObject({ + actionId: '1', + name: 'test name', + action: 'execute', + message: 'action execution start', + namespace: 'default', + savedObjects: [ + { + id: '2', + type: 'action', + typeId: '.email', + relation: 'primary', + }, + ], + }) + ).toStrictEqual({ + event: { + action: 'execute', + kind: 'action', + }, + kibana: { + saved_objects: [ + { + id: '2', + namespace: 'default', + rel: 'primary', + type: 'action', + type_id: '.email', + }, + ], + }, + message: 'action execution start', + }); + }); + test('created action event "execute-timeout"', async () => { expect( createActionEventLogRecordObject({ diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts index 5d556398dc668..2632ead26a477 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash'; +import { isEmpty, set } from 'lodash'; import { IEvent, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; import { RelatedSavedObjects } from './related_saved_objects'; @@ -38,6 +38,17 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec const { action, message, task, namespace, executionId, spaceId, consumer, relatedSavedObjects } = params; + const kibanaAlertRule = { + ...(consumer ? { consumer } : {}), + ...(executionId + ? { + execution: { + uuid: executionId, + }, + } + : {}), + }; + const event: Event = { ...(params.timestamp ? { '@timestamp': params.timestamp } : {}), event: { @@ -45,18 +56,7 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec kind: 'action', }, kibana: { - alert: { - rule: { - ...(consumer ? { consumer } : {}), - ...(executionId - ? { - execution: { - uuid: executionId, - }, - } - : {}), - }, - }, + ...(!isEmpty(kibanaAlertRule) ? { alert: { rule: kibanaAlertRule } } : {}), saved_objects: params.savedObjects.map((so) => ({ ...(so.relation ? { rel: so.relation } : {}), type: so.type, diff --git a/x-pack/plugins/actions/server/lib/get_custom_agents.test.ts b/x-pack/plugins/actions/server/lib/get_custom_agents.test.ts index 9bf1e26f1d374..7d61e4b4c6d43 100644 --- a/x-pack/plugins/actions/server/lib/get_custom_agents.test.ts +++ b/x-pack/plugins/actions/server/lib/get_custom_agents.test.ts @@ -6,7 +6,7 @@ */ import { Agent as HttpsAgent } from 'https'; -import HttpProxyAgent from 'http-proxy-agent'; +import { HttpProxyAgent } from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { Logger } from '@kbn/core/server'; import { getCustomAgents } from './get_custom_agents'; diff --git a/x-pack/plugins/actions/server/lib/get_custom_agents.ts b/x-pack/plugins/actions/server/lib/get_custom_agents.ts index 49eca54afcde7..220abeb6cc928 100644 --- a/x-pack/plugins/actions/server/lib/get_custom_agents.ts +++ b/x-pack/plugins/actions/server/lib/get_custom_agents.ts @@ -7,7 +7,7 @@ import { Agent as HttpAgent } from 'http'; import { Agent as HttpsAgent, AgentOptions } from 'https'; -import HttpProxyAgent from 'http-proxy-agent'; +import { HttpProxyAgent } from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '../actions_config'; diff --git a/x-pack/plugins/actions/server/mocks.ts b/x-pack/plugins/actions/server/mocks.ts index 3b8155818452f..4d5846de9528f 100644 --- a/x-pack/plugins/actions/server/mocks.ts +++ b/x-pack/plugins/actions/server/mocks.ts @@ -17,6 +17,7 @@ import { PluginSetupContract, PluginStartContract, renderActionParameterTemplate import { Services } from './types'; import { actionsAuthorizationMock } from './authorization/actions_authorization.mock'; import { ConnectorTokenClient } from './lib/connector_token_client'; +import { unsecuredActionsClientMock } from './unsecured_actions_client/unsecured_actions_client.mock'; export { actionsAuthorizationMock }; export { actionsClientMock }; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -38,6 +39,7 @@ const createStartMock = () => { isActionTypeEnabled: jest.fn(), isActionExecutable: jest.fn(), getActionsClientWithRequest: jest.fn().mockResolvedValue(actionsClientMock.create()), + getUnsecuredActionsClient: jest.fn().mockResolvedValue(unsecuredActionsClientMock.create()), getActionsAuthorizationWithRequest: jest .fn() .mockReturnValue(actionsAuthorizationMock.create()), diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 749fc7a21ebdf..e24ac8247bfd8 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -101,6 +101,11 @@ import { createSubActionConnectorFramework } from './sub_action_framework'; import { IServiceAbstract, SubActionConnectorType } from './sub_action_framework/types'; import { SubActionConnector } from './sub_action_framework/sub_action_connector'; import { CaseConnector } from './sub_action_framework/case'; +import { + IUnsecuredActionsClient, + UnsecuredActionsClient, +} from './unsecured_actions_client/unsecured_actions_client'; +import { createBulkUnsecuredExecutionEnqueuerFunction } from './create_unsecured_execute_function'; export interface PluginSetupContract { registerType< @@ -138,6 +143,8 @@ export interface PluginStartContract { preconfiguredActions: PreConfiguredAction[]; + getUnsecuredActionsClient(): IUnsecuredActionsClient; + renderActionParameterTemplates( actionTypeId: string, actionId: string, @@ -453,6 +460,21 @@ export class ActionsPlugin implements Plugin { + const internalSavedObjectsRepository = core.savedObjects.createInternalRepository([ + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + ]); + + return new UnsecuredActionsClient({ + internalSavedObjectsRepository, + executionEnqueuer: createBulkUnsecuredExecutionEnqueuerFunction({ + taskManager: plugins.taskManager, + connectorTypeRegistry: actionTypeRegistry!, + preconfiguredConnectors: preconfiguredActions, + }), + }); + }; + // Ensure the public API cannot be used to circumvent authorization // using our legacy exemption mechanism by passing in a legacy SO // as authorizationContext which would then set a Legacy AuthorizationMode @@ -533,6 +555,7 @@ export class ActionsPlugin implements Plugin renderActionParameterTemplates(actionTypeRegistry, ...args), diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.mock.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.mock.ts new file mode 100644 index 0000000000000..eb8d4de53e7f3 --- /dev/null +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.mock.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 { IUnsecuredActionsClient } from './unsecured_actions_client'; + +export type UnsecuredActionsClientMock = jest.Mocked; + +const createUnsecuredActionsClientMock = () => { + const mocked: UnsecuredActionsClientMock = { + bulkEnqueueExecution: jest.fn(), + }; + return mocked; +}; + +export const unsecuredActionsClientMock = { + create: createUnsecuredActionsClientMock, +}; diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.test.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.test.ts new file mode 100644 index 0000000000000..c863e943b8dc0 --- /dev/null +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UnsecuredActionsClient } from './unsecured_actions_client'; +import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; + +const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); +const executionEnqueuer = jest.fn(); + +let unsecuredActionsClient: UnsecuredActionsClient; + +beforeEach(() => { + jest.resetAllMocks(); + unsecuredActionsClient = new UnsecuredActionsClient({ + internalSavedObjectsRepository, + executionEnqueuer, + }); +}); + +describe('bulkEnqueueExecution()', () => { + test('throws error when enqueuing execution with not allowed requester id', async () => { + const opts = [ + { + id: 'preconfigured1', + params: {}, + executionId: '123abc', + }, + { + id: 'preconfigured2', + params: {}, + executionId: '456def', + }, + ]; + await expect( + unsecuredActionsClient.bulkEnqueueExecution('badId', opts) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"badId\\" feature is not allow-listed for UnsecuredActionsClient access."` + ); + }); + + test('calls the executionEnqueuer with the appropriate parameters', async () => { + const opts = [ + { + id: 'preconfigured1', + params: {}, + executionId: '123abc', + }, + { + id: 'preconfigured2', + params: {}, + executionId: '456def', + }, + ]; + await expect( + unsecuredActionsClient.bulkEnqueueExecution('notifications', opts) + ).resolves.toMatchInlineSnapshot(`undefined`); + + expect(executionEnqueuer).toHaveBeenCalledWith(internalSavedObjectsRepository, opts); + }); +}); diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts new file mode 100644 index 0000000000000..333490389013a --- /dev/null +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts @@ -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 { ISavedObjectsRepository } from '@kbn/core/server'; +import { + BulkUnsecuredExecutionEnqueuer, + ExecuteOptions, +} from '../create_unsecured_execute_function'; + +// allowlist for features wanting access to the unsecured actions client +// which allows actions to be enqueued for execution without a user request +const ALLOWED_REQUESTER_IDS = [ + 'notifications', + // For functional testing + 'functional_tester', +]; + +export interface UnsecuredActionsClientOpts { + internalSavedObjectsRepository: ISavedObjectsRepository; + executionEnqueuer: BulkUnsecuredExecutionEnqueuer; +} + +export interface IUnsecuredActionsClient { + bulkEnqueueExecution: (requesterId: string, actionsToExecute: ExecuteOptions[]) => Promise; +} + +export class UnsecuredActionsClient { + private readonly internalSavedObjectsRepository: ISavedObjectsRepository; + private readonly executionEnqueuer: BulkUnsecuredExecutionEnqueuer; + + constructor(params: UnsecuredActionsClientOpts) { + this.executionEnqueuer = params.executionEnqueuer; + this.internalSavedObjectsRepository = params.internalSavedObjectsRepository; + } + + public async bulkEnqueueExecution( + requesterId: string, + actionsToExecute: ExecuteOptions[] + ): Promise { + // Check that requesterId is allowed + if (!ALLOWED_REQUESTER_IDS.includes(requesterId)) { + throw new Error( + `"${requesterId}" feature is not allow-listed for UnsecuredActionsClient access.` + ); + } + return this.executionEnqueuer(this.internalSavedObjectsRepository, actionsToExecute); + } +} diff --git a/x-pack/plugins/aiops/server/lib/is_request_aborted_error.test.ts b/x-pack/plugins/aiops/server/lib/is_request_aborted_error.test.ts new file mode 100644 index 0000000000000..ee9725dedda4b --- /dev/null +++ b/x-pack/plugins/aiops/server/lib/is_request_aborted_error.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isRequestAbortedError } from './is_request_aborted_error'; + +describe('isRequestAbortedError', () => { + it('returns false for a string', () => { + expect(isRequestAbortedError('the-error')).toBe(false); + }); + it('returns false for a an object without a name field', () => { + expect(isRequestAbortedError({ error: 'the-error' })).toBe(false); + }); + it(`returns false for a an object with a name field other than 'RequestAbortedError'`, () => { + expect(isRequestAbortedError({ name: 'the-error' })).toBe(false); + }); + it(`returns true for a an object with a name field that contains 'RequestAbortedError'`, () => { + expect(isRequestAbortedError({ name: 'RequestAbortedError' })).toBe(true); + }); +}); diff --git a/x-pack/plugins/aiops/server/lib/is_request_aborted_error.ts b/x-pack/plugins/aiops/server/lib/is_request_aborted_error.ts new file mode 100644 index 0000000000000..b80256dcd8639 --- /dev/null +++ b/x-pack/plugins/aiops/server/lib/is_request_aborted_error.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + +interface RequestAbortedError extends Error { + name: 'RequestAbortedError'; +} + +export function isRequestAbortedError(arg: unknown): arg is RequestAbortedError { + return isPopulatedObject(arg, ['name']) && arg.name === 'RequestAbortedError'; +} diff --git a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts index c61e1915f68f7..2468df9df8237 100644 --- a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts +++ b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts @@ -34,6 +34,7 @@ import { } from '../../common/api/explain_log_rate_spikes'; import { API_ENDPOINT } from '../../common/api'; +import { isRequestAbortedError } from '../lib/is_request_aborted_error'; import type { AiopsLicense } from '../types'; import { fetchChangePointPValues } from './queries/fetch_change_point_p_values'; @@ -92,6 +93,7 @@ export const defineExplainLogRateSpikesRoute = ( const client = (await context.core).elasticsearch.client.asCurrentUser; const controller = new AbortController(); + const abortSignal = controller.signal; let isRunning = false; let loaded = 0; @@ -129,9 +131,13 @@ export const defineExplainLogRateSpikesRoute = ( } function end() { - isRunning = false; - logDebugMessage('Ending analysis.'); - streamEnd(); + if (isRunning) { + isRunning = false; + logDebugMessage('Ending analysis.'); + streamEnd(); + } else { + logDebugMessage('end() was called again with isRunning already being false.'); + } } function endWithUpdatedLoadingState() { @@ -178,10 +184,12 @@ export const defineExplainLogRateSpikesRoute = ( let fieldCandidates: Awaited>; try { - fieldCandidates = await fetchFieldCandidates(client, request.body); + fieldCandidates = await fetchFieldCandidates(client, request.body, abortSignal); } catch (e) { - logger.error(`Failed to fetch field candidates, got: \n${e.toString()}`); - pushError(`Failed to fetch field candidates.`); + if (!isRequestAbortedError(e)) { + logger.error(`Failed to fetch field candidates, got: \n${e.toString()}`); + pushError(`Failed to fetch field candidates.`); + } end(); return; } @@ -208,16 +216,20 @@ export const defineExplainLogRateSpikesRoute = ( if (fieldCandidates.length === 0) { endWithUpdatedLoadingState(); } else if (shouldStop) { + logDebugMessage('shouldStop after fetching field candidates.'); end(); return; } const changePoints: ChangePoint[] = []; const fieldsToSample = new Set(); - const chunkSize = 10; + + // Don't use more than 10 here otherwise Kibana will emit an error + // regarding a limit of abort signal listeners of more than 10. + const CHUNK_SIZE = 10; let chunkCount = 0; - const fieldCandidatesChunks = chunk(fieldCandidates, chunkSize); + const fieldCandidatesChunks = chunk(fieldCandidates, CHUNK_SIZE); logDebugMessage('Fetch p-values.'); @@ -233,16 +245,18 @@ export const defineExplainLogRateSpikesRoute = ( request.body, fieldCandidatesChunk, logger, - pushError + pushError, + abortSignal ); } catch (e) { - logger.error( - `Failed to fetch p-values for ${JSON.stringify( - fieldCandidatesChunk - )}, got: \n${e.toString()}` - ); - pushError(`Failed to fetch p-values for ${JSON.stringify(fieldCandidatesChunk)}.`); - // Still continue the analysis even if chunks of p-value queries fail. + if (!isRequestAbortedError(e)) { + logger.error( + `Failed to fetch p-values for ${JSON.stringify( + fieldCandidatesChunk + )}, got: \n${e.toString()}` + ); + pushError(`Failed to fetch p-values for ${JSON.stringify(fieldCandidatesChunk)}.`); + } // Still continue the analysis even if chunks of p-value queries fail. continue; } @@ -267,7 +281,7 @@ export const defineExplainLogRateSpikesRoute = ( defaultMessage: 'Identified {fieldValuePairsCount, plural, one {# significant field/value pair} other {# significant field/value pairs}}.', values: { - fieldValuePairsCount: changePoints?.length ?? 0, + fieldValuePairsCount: changePoints.length, }, } ), @@ -276,13 +290,12 @@ export const defineExplainLogRateSpikesRoute = ( if (shouldStop) { logDebugMessage('shouldStop fetching p-values.'); - end(); return; } } - if (changePoints?.length === 0) { + if (changePoints.length === 0) { logDebugMessage('Stopping analysis, did not find change points.'); endWithUpdatedLoadingState(); return; @@ -305,12 +318,15 @@ export const defineExplainLogRateSpikesRoute = ( histogramFields, // samplerShardSize -1, - undefined + undefined, + abortSignal )) as [NumericChartData] )[0]; } catch (e) { - logger.error(`Failed to fetch the overall histogram data, got: \n${e.toString()}`); - pushError(`Failed to fetch overall histogram data.`); + if (!isRequestAbortedError(e)) { + logger.error(`Failed to fetch the overall histogram data, got: \n${e.toString()}`); + pushError(`Failed to fetch overall histogram data.`); + } // Still continue the analysis even if loading the overall histogram fails. } @@ -329,6 +345,12 @@ export const defineExplainLogRateSpikesRoute = ( ); } + if (shouldStop) { + logDebugMessage('shouldStop after fetching overall histogram.'); + end(); + return; + } + if (groupingEnabled) { logDebugMessage('Group results.'); @@ -374,9 +396,16 @@ export const defineExplainLogRateSpikesRoute = ( request.body.deviationMin, request.body.deviationMax, logger, - pushError + pushError, + abortSignal ); + if (shouldStop) { + logDebugMessage('shouldStop after fetching frequent_items.'); + end(); + return; + } + if (fields.length > 0 && df.length > 0) { // The way the `frequent_items` aggregations works could return item sets that include // field/value pairs that are not part of the original list of significant change points. @@ -517,172 +546,208 @@ export const defineExplainLogRateSpikesRoute = ( pushHistogramDataLoadingState(); - logDebugMessage('Fetch group histograms.'); + if (shouldStop) { + logDebugMessage('shouldStop after grouping.'); + end(); + return; + } - await asyncForEach(changePointGroups, async (cpg) => { - if (overallTimeSeries !== undefined) { - const histogramQuery = { - bool: { - filter: cpg.group.map((d) => ({ - term: { [d.fieldName]: d.fieldValue }, - })), - }, - }; + logDebugMessage(`Fetch ${changePointGroups.length} group histograms.`); - let cpgTimeSeries: NumericChartData; - try { - cpgTimeSeries = ( - (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ - { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], - }, - ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData] - )[0]; - } catch (e) { - logger.error( - `Failed to fetch the histogram data for group #${ - cpg.id - }, got: \n${e.toString()}` - ); - pushError(`Failed to fetch the histogram data for group #${cpg.id}.`); - return; - } - const histogram = - overallTimeSeries.data.map((o, i) => { - const current = cpgTimeSeries.data.find( - (d1) => d1.key_as_string === o.key_as_string - ) ?? { - doc_count: 0, - }; - return { - key: o.key, - key_as_string: o.key_as_string ?? '', - doc_count_change_point: current.doc_count, - doc_count_overall: Math.max(0, o.doc_count - current.doc_count), - }; - }) ?? []; + const changePointGroupsChunks = chunk(changePointGroups, CHUNK_SIZE); - push( - addChangePointsGroupHistogramAction([ - { - id: cpg.id, - histogram, - }, - ]) - ); + for (const changePointGroupsChunk of changePointGroupsChunks) { + if (shouldStop) { + logDebugMessage('shouldStop abort fetching group histograms.'); + end(); + return; } - }); + + await asyncForEach(changePointGroupsChunk, async (cpg) => { + if (overallTimeSeries !== undefined) { + const histogramQuery = { + bool: { + filter: cpg.group.map((d) => ({ + term: { [d.fieldName]: d.fieldValue }, + })), + }, + }; + + let cpgTimeSeries: NumericChartData; + try { + cpgTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined, + abortSignal + )) as [NumericChartData] + )[0]; + } catch (e) { + if (!isRequestAbortedError(e)) { + logger.error( + `Failed to fetch the histogram data for group #${ + cpg.id + }, got: \n${e.toString()}` + ); + pushError(`Failed to fetch the histogram data for group #${cpg.id}.`); + } + return; + } + const histogram = + overallTimeSeries.data.map((o, i) => { + const current = cpgTimeSeries.data.find( + (d1) => d1.key_as_string === o.key_as_string + ) ?? { + doc_count: 0, + }; + return { + key: o.key, + key_as_string: o.key_as_string ?? '', + doc_count_change_point: current.doc_count, + doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + }; + }) ?? []; + + push( + addChangePointsGroupHistogramAction([ + { + id: cpg.id, + histogram, + }, + ]) + ); + } + }); + } } } catch (e) { - logger.error( - `Failed to transform field/value pairs into groups, got: \n${e.toString()}` - ); - pushError(`Failed to transform field/value pairs into groups.`); + if (!isRequestAbortedError(e)) { + logger.error( + `Failed to transform field/value pairs into groups, got: \n${e.toString()}` + ); + pushError(`Failed to transform field/value pairs into groups.`); + } } } loaded += PROGRESS_STEP_HISTOGRAMS_GROUPS; - logDebugMessage('Fetch field/value histograms.'); + logDebugMessage(`Fetch ${changePoints.length} field/value histograms.`); // time series filtered by fields - if (changePoints && overallTimeSeries !== undefined) { - await asyncForEach(changePoints, async (cp) => { - if (overallTimeSeries !== undefined) { - const histogramQuery = { - bool: { - filter: [ - { - term: { [cp.fieldName]: cp.fieldValue }, - }, - ], - }, - }; - - let cpTimeSeries: NumericChartData; - - try { - cpTimeSeries = ( - (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ + if (changePoints.length > 0 && overallTimeSeries !== undefined) { + const changePointsChunks = chunk(changePoints, CHUNK_SIZE); + + for (const changePointsChunk of changePointsChunks) { + if (shouldStop) { + logDebugMessage('shouldStop abort fetching field/value histograms.'); + end(); + return; + } + + await asyncForEach(changePointsChunk, async (cp) => { + if (overallTimeSeries !== undefined) { + const histogramQuery = { + bool: { + filter: [ { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], + term: { [cp.fieldName]: cp.fieldValue }, }, ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData] - )[0]; - } catch (e) { - logger.error( - `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${ - cp.fieldValue - }", got: \n${e.toString()}` - ); - pushError( - `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${cp.fieldValue}".` + }, + }; + + let cpTimeSeries: NumericChartData; + + try { + cpTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined, + abortSignal + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${ + cp.fieldValue + }", got: \n${e.toString()}` + ); + pushError( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${cp.fieldValue}".` + ); + return; + } + + const histogram = + overallTimeSeries.data.map((o, i) => { + const current = cpTimeSeries.data.find( + (d1) => d1.key_as_string === o.key_as_string + ) ?? { + doc_count: 0, + }; + return { + key: o.key, + key_as_string: o.key_as_string ?? '', + doc_count_change_point: current.doc_count, + doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + }; + }) ?? []; + + const { fieldName, fieldValue } = cp; + + loaded += (1 / changePoints.length) * PROGRESS_STEP_HISTOGRAMS; + pushHistogramDataLoadingState(); + push( + addChangePointsHistogramAction([ + { + fieldName, + fieldValue, + histogram, + }, + ]) ); - return; } - - const histogram = - overallTimeSeries.data.map((o, i) => { - const current = cpTimeSeries.data.find( - (d1) => d1.key_as_string === o.key_as_string - ) ?? { - doc_count: 0, - }; - return { - key: o.key, - key_as_string: o.key_as_string ?? '', - doc_count_change_point: current.doc_count, - doc_count_overall: Math.max(0, o.doc_count - current.doc_count), - }; - }) ?? []; - - const { fieldName, fieldValue } = cp; - - loaded += (1 / changePoints.length) * PROGRESS_STEP_HISTOGRAMS; - pushHistogramDataLoadingState(); - push( - addChangePointsHistogramAction([ - { - fieldName, - fieldValue, - histogram, - }, - ]) - ); - } - }); + }); + } } endWithUpdatedLoadingState(); } catch (e) { - logger.error(`Explain log rate spikes analysis failed to finish, got: \n${e.toString()}`); - pushError(`Explain log rate spikes analysis failed to finish.`); + if (!isRequestAbortedError(e)) { + logger.error( + `Explain log rate spikes analysis failed to finish, got: \n${e.toString()}` + ); + pushError(`Explain log rate spikes analysis failed to finish.`); + } end(); } } diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts index 0fb7f90c89c12..08165db084670 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts @@ -13,6 +13,8 @@ import { ChangePoint } from '@kbn/ml-agg-utils'; import { SPIKE_ANALYSIS_THRESHOLD } from '../../../common/constants'; import type { AiopsExplainLogRateSpikesSchema } from '../../../common/api/explain_log_rate_spikes'; +import { isRequestAbortedError } from '../../lib/is_request_aborted_error'; + import { getQueryWithParams } from './get_query_with_params'; import { getRequestBase } from './get_request_base'; @@ -95,23 +97,49 @@ export const fetchChangePointPValues = async ( params: AiopsExplainLogRateSpikesSchema, fieldNames: string[], logger: Logger, - emitError: (m: string) => void + emitError: (m: string) => void, + abortSignal?: AbortSignal ): Promise => { const result: ChangePoint[] = []; - for (const fieldName of fieldNames) { - const request = getChangePointRequest(params, fieldName); - const resp = await esClient.search(request); - - if (resp.aggregations === undefined) { + const settledPromises = await Promise.allSettled( + fieldNames.map((fieldName) => + esClient.search( + getChangePointRequest(params, fieldName), + { + signal: abortSignal, + maxRetries: 0, + } + ) + ) + ); + + function reportError(fieldName: string, error: unknown) { + if (!isRequestAbortedError(error)) { logger.error( `Failed to fetch p-value aggregation for fieldName "${fieldName}", got: \n${JSON.stringify( - resp, + error, null, 2 )}` ); emitError(`Failed to fetch p-value aggregation for fieldName "${fieldName}".`); + } + } + + for (const [index, settledPromise] of settledPromises.entries()) { + const fieldName = fieldNames[index]; + + if (settledPromise.status === 'rejected') { + reportError(fieldName, settledPromise.reason); + // Still continue the analysis even if individual p-value queries fail. + continue; + } + + const resp = settledPromise.value; + + if (resp.aggregations === undefined) { + reportError(fieldName, resp); // Still continue the analysis even if individual p-value queries fail. continue; } diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_field_candidates.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_field_candidates.ts index 7a761d91c0da5..036d8c0f51fcf 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_field_candidates.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_field_candidates.ts @@ -47,14 +47,18 @@ export const getRandomDocsRequest = ( export const fetchFieldCandidates = async ( esClient: ElasticsearchClient, - params: AiopsExplainLogRateSpikesSchema + params: AiopsExplainLogRateSpikesSchema, + abortSignal?: AbortSignal ): Promise => { const { index } = params; // Get all supported fields - const respMapping = await esClient.fieldCaps({ - index, - fields: '*', - }); + const respMapping = await esClient.fieldCaps( + { + index, + fields: '*', + }, + { signal: abortSignal, maxRetries: 0 } + ); const finalFieldCandidates: Set = new Set([]); const acceptableFields: Set = new Set(); @@ -69,7 +73,10 @@ export const fetchFieldCandidates = async ( } }); - const resp = await esClient.search(getRandomDocsRequest(params)); + const resp = await esClient.search(getRandomDocsRequest(params), { + signal: abortSignal, + maxRetries: 0, + }); const sampledDocs = resp.hits.hits.map((d) => d.fields ?? {}); // Get all field names for each returned doc and flatten it diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts index c9444aaca22af..aaf9af283c3e1 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts @@ -56,7 +56,8 @@ export async function fetchFrequentItems( deviationMin: number, deviationMax: number, logger: Logger, - emitError: (m: string) => void + emitError: (m: string) => void, + abortSignal?: AbortSignal ) { // get unique fields from change points const fields = [...new Set(changePoints.map((t) => t.fieldName))]; @@ -127,7 +128,7 @@ export async function fetchFrequentItems( track_total_hits: true, }, }, - { maxRetries: 0 } + { signal: abortSignal, maxRetries: 0 } ); if (body.aggregations === undefined) { diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts index 7138aabe9d263..2b403684c8d53 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts @@ -51,6 +51,7 @@ export enum WriteOperations { UnmuteAlert = 'unmuteAlert', Snooze = 'snooze', BulkEdit = 'bulkEdit', + BulkDelete = 'bulkDelete', Unsnooze = 'unsnooze', } diff --git a/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.test.ts b/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.test.ts index e86cd98f4a490..b36dfed980b02 100644 --- a/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.test.ts +++ b/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.test.ts @@ -25,7 +25,7 @@ const rule = { describe('wrapScopedClusterClient', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts b/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts index 9c10e619e3ebb..55dc0a5d62161 100644 --- a/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts +++ b/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts @@ -35,7 +35,7 @@ const createSearchSourceClientMock = () => { describe('wrapSearchSourceClient', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/alerting/server/routes/bulk_delete_rules.test.ts b/x-pack/plugins/alerting/server/routes/bulk_delete_rules.test.ts new file mode 100644 index 0000000000000..8fc27cfbc0054 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/bulk_delete_rules.test.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { httpServiceMock } from '@kbn/core/server/mocks'; + +import { bulkDeleteRulesRoute } from './bulk_delete_rules'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { rulesClientMock } from '../rules_client.mock'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; +import { verifyApiAccess } from '../lib/license_api_access'; + +const rulesClient = rulesClientMock.create(); + +jest.mock('../lib/license_api_access', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('bulkDeleteRulesRoute', () => { + const bulkDeleteRequest = { filter: '' }; + const bulkDeleteResult = { errors: [], total: 1, taskIdsFailedToBeDeleted: [] }; + + it('should delete rules with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + bulkDeleteRulesRoute({ router, licenseState }); + + const [config, handler] = router.patch.mock.calls[0]; + + expect(config.path).toBe('/internal/alerting/rules/_bulk_delete'); + + rulesClient.bulkDeleteRules.mockResolvedValueOnce(bulkDeleteResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + body: bulkDeleteRequest, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toEqual({ + body: bulkDeleteResult, + }); + + expect(rulesClient.bulkDeleteRules).toHaveBeenCalledTimes(1); + expect(rulesClient.bulkDeleteRules.mock.calls[0]).toEqual([bulkDeleteRequest]); + + expect(res.ok).toHaveBeenCalled(); + }); + + it('ensures the license allows bulk deleting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + rulesClient.bulkDeleteRules.mockResolvedValueOnce(bulkDeleteResult); + + bulkDeleteRulesRoute({ router, licenseState }); + + const [, handler] = router.patch.mock.calls[0]; + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + body: bulkDeleteRequest, + } + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents bulk deleting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('Failure'); + }); + + bulkDeleteRulesRoute({ router, licenseState }); + + const [, handler] = router.patch.mock.calls[0]; + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + body: bulkDeleteRequest, + } + ); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: Failure]`); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + bulkDeleteRulesRoute({ router, licenseState }); + + const [, handler] = router.patch.mock.calls[0]; + + rulesClient.bulkDeleteRules.mockRejectedValue( + new RuleTypeDisabledError('Fail', 'license_invalid') + ); + + const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/bulk_delete_rules.ts b/x-pack/plugins/alerting/server/routes/bulk_delete_rules.ts new file mode 100644 index 0000000000000..1eca663de21a8 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/bulk_delete_rules.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { IRouter } from '@kbn/core/server'; +import { verifyAccessAndContext, handleDisabledApiKeysError } from './lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; +import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; + +export const bulkDeleteRulesRoute = ({ + router, + licenseState, +}: { + router: IRouter; + licenseState: ILicenseState; +}) => { + router.patch( + { + path: `${INTERNAL_BASE_ALERTING_API_PATH}/rules/_bulk_delete`, + validate: { + body: schema.object({ + filter: schema.maybe(schema.string()), + ids: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1, maxSize: 1000 })), + }), + }, + }, + handleDisabledApiKeysError( + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async (context, req, res) => { + const rulesClient = (await context.alerting).getRulesClient(); + const { filter, ids } = req.body; + + try { + const result = await rulesClient.bulkDeleteRules({ filter, ids }); + return res.ok({ body: result }); + } catch (e) { + if (e instanceof RuleTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index de9e2f112d9e9..dfb9c290af3d2 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -38,6 +38,7 @@ import { bulkEditInternalRulesRoute } from './bulk_edit_rules'; import { snoozeRuleRoute } from './snooze_rule'; import { unsnoozeRuleRoute } from './unsnooze_rule'; import { runSoonRoute } from './run_soon'; +import { bulkDeleteRulesRoute } from './bulk_delete_rules'; export interface RouteOptions { router: IRouter; @@ -76,6 +77,7 @@ export function defineRoutes(opts: RouteOptions) { unmuteAlertRoute(router, licenseState); updateRuleApiKeyRoute(router, licenseState); bulkEditInternalRulesRoute(router, licenseState); + bulkDeleteRulesRoute({ router, licenseState }); snoozeRuleRoute(router, licenseState); unsnoozeRuleRoute(router, licenseState); runSoonRoute(router, licenseState); diff --git a/x-pack/plugins/alerting/server/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client.mock.ts index 2092b98e48c0d..aa29e64d2f460 100644 --- a/x-pack/plugins/alerting/server/rules_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client.mock.ts @@ -36,6 +36,7 @@ const createRulesClientMock = () => { getActionErrorLog: jest.fn(), getSpaceId: jest.fn(), bulkEdit: jest.fn(), + bulkDeleteRules: jest.fn(), snooze: jest.fn(), unsnooze: jest.fn(), calculateIsSnoozedUntil: jest.fn(), diff --git a/x-pack/plugins/alerting/server/rules_client/lib/index.ts b/x-pack/plugins/alerting/server/rules_client/lib/index.ts index f3f11589d2966..a221327d938ef 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/index.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/index.ts @@ -8,5 +8,6 @@ export { mapSortField } from './map_sort_field'; export { validateOperationOnAttributes } from './validate_attributes'; export { retryIfBulkEditConflicts } from './retry_if_bulk_edit_conflicts'; +export { retryIfBulkDeleteConflicts } from './retry_if_bulk_delete_conflicts'; export { applyBulkEditOperation } from './apply_bulk_edit_operation'; export { buildKueryNodeFilter } from './build_kuery_node_filter'; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.test.ts new file mode 100644 index 0000000000000..32a18ea7f0984 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KueryNode } from '@kbn/es-query'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; + +import { retryIfBulkDeleteConflicts } from './retry_if_bulk_delete_conflicts'; +import { RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; + +const mockFilter: KueryNode = { + type: 'function', + value: 'mock', +}; + +const mockLogger = loggingSystemMock.create().get(); + +const mockSuccessfulResult = { + apiKeysToInvalidate: ['apiKey1'], + errors: [], + taskIdsToDelete: ['taskId1'], +}; + +const error409 = { + message: 'some fake message', + status: 409, + rule: { + id: 'fake_rule_id', + name: 'fake rule name', + }, +}; + +const getOperationConflictsTimes = (times: number) => { + return async () => { + conflictOperationMock(); + times--; + if (times >= 0) { + return { + apiKeysToInvalidate: [], + taskIdsToDelete: [], + errors: [error409], + }; + } + return mockSuccessfulResult; + }; +}; + +const OperationSuccessful = async () => mockSuccessfulResult; +const conflictOperationMock = jest.fn(); + +describe('retryIfBulkDeleteConflicts', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + test('should work when operation is successful', async () => { + const result = await retryIfBulkDeleteConflicts(mockLogger, OperationSuccessful, mockFilter); + + expect(result).toEqual(mockSuccessfulResult); + }); + + test('should throw error when operation fails', async () => { + await expect( + retryIfBulkDeleteConflicts( + mockLogger, + async () => { + throw Error('Test failure'); + }, + mockFilter + ) + ).rejects.toThrowError('Test failure'); + }); + + test(`should return conflict errors when number of retries exceeds ${RETRY_IF_CONFLICTS_ATTEMPTS}`, async () => { + const result = await retryIfBulkDeleteConflicts( + mockLogger, + getOperationConflictsTimes(RETRY_IF_CONFLICTS_ATTEMPTS + 1), + mockFilter + ); + + expect(result.errors).toEqual([error409]); + expect(mockLogger.warn).toBeCalledWith('Bulk delete rules conflicts, exceeded retries'); + }); + + for (let i = 1; i <= RETRY_IF_CONFLICTS_ATTEMPTS; i++) { + test(`should work when operation conflicts ${i} times`, async () => { + const result = await retryIfBulkDeleteConflicts( + mockLogger, + getOperationConflictsTimes(i), + mockFilter + ); + + expect(conflictOperationMock.mock.calls.length).toBe(i + 1); + expect(result).toStrictEqual(mockSuccessfulResult); + }); + } +}); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.ts new file mode 100644 index 0000000000000..529055b85e44a --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_delete_conflicts.ts @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import pMap from 'p-map'; +import { chunk } from 'lodash'; +import { KueryNode } from '@kbn/es-query'; +import { Logger } from '@kbn/core/server'; +import { convertRuleIdsToKueryNode } from '../../lib'; +import { BulkDeleteError } from '../rules_client'; +import { waitBeforeNextRetry, RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; + +const MAX_RULES_IDS_IN_RETRY = 1000; + +export type BulkDeleteOperation = (filter: KueryNode | null) => Promise<{ + apiKeysToInvalidate: string[]; + errors: BulkDeleteError[]; + taskIdsToDelete: string[]; +}>; + +interface ReturnRetry { + apiKeysToInvalidate: string[]; + errors: BulkDeleteError[]; + taskIdsToDelete: string[]; +} + +/** + * Retries BulkDelete requests + * If in response are presents conflicted savedObjects(409 statusCode), this util constructs filter with failed SO ids and retries bulkDelete operation until + * all SO updated or number of retries exceeded + * @param logger + * @param bulkEditOperation + * @param filter - KueryNode filter + * @param retries - number of retries left + * @param accApiKeysToInvalidate - accumulated apiKeys that need to be invalidated + * @param accErrors - accumulated conflict errors + * @param accTaskIdsToDelete - accumulated task ids + * @returns Promise + */ +export const retryIfBulkDeleteConflicts = async ( + logger: Logger, + bulkDeleteOperation: BulkDeleteOperation, + filter: KueryNode | null, + retries: number = RETRY_IF_CONFLICTS_ATTEMPTS, + accApiKeysToInvalidate: string[] = [], + accErrors: BulkDeleteError[] = [], + accTaskIdsToDelete: string[] = [] +): Promise => { + try { + const { + apiKeysToInvalidate: currentApiKeysToInvalidate, + errors: currentErrors, + taskIdsToDelete: currentTaskIdsToDelete, + } = await bulkDeleteOperation(filter); + + const apiKeysToInvalidate = [...accApiKeysToInvalidate, ...currentApiKeysToInvalidate]; + const taskIdsToDelete = [...accTaskIdsToDelete, ...currentTaskIdsToDelete]; + const errors = + retries <= 0 + ? [...accErrors, ...currentErrors] + : [...accErrors, ...currentErrors.filter((error) => error.status !== 409)]; + + const ruleIdsWithConflictError = currentErrors.reduce((acc, error) => { + if (error.status === 409) { + return [...acc, error.rule.id]; + } + return acc; + }, []); + + if (ruleIdsWithConflictError.length === 0) { + return { + apiKeysToInvalidate, + errors, + taskIdsToDelete, + }; + } + + if (retries <= 0) { + logger.warn('Bulk delete rules conflicts, exceeded retries'); + + return { + apiKeysToInvalidate, + errors, + taskIdsToDelete, + }; + } + + logger.debug( + `Bulk delete rules conflicts, retrying ..., ${ruleIdsWithConflictError.length} saved objects conflicted` + ); + + await waitBeforeNextRetry(retries); + + // here, we construct filter query with ids. But, due to a fact that number of conflicted saved objects can exceed few thousands we can encounter following error: + // "all shards failed: search_phase_execution_exception: [query_shard_exception] Reason: failed to create query: maxClauseCount is set to 2621" + // That's why we chunk processing ids into pieces by size equals to MAX_RULES_IDS_IN_RETRY + return ( + await pMap( + chunk(ruleIdsWithConflictError, MAX_RULES_IDS_IN_RETRY), + async (queryIds) => + retryIfBulkDeleteConflicts( + logger, + bulkDeleteOperation, + convertRuleIdsToKueryNode(queryIds), + retries - 1, + apiKeysToInvalidate, + errors, + taskIdsToDelete + ), + { + concurrency: 1, + } + ) + ).reduce( + (acc, item) => { + return { + apiKeysToInvalidate: [...acc.apiKeysToInvalidate, ...item.apiKeysToInvalidate], + errors: [...acc.errors, ...item.errors], + taskIdsToDelete: [...acc.taskIdsToDelete, ...item.taskIdsToDelete], + }; + }, + { apiKeysToInvalidate: [], errors: [], taskIdsToDelete: [] } + ); + } catch (err) { + throw err; + } +}; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.test.ts index ae2a83614ac20..5053b367b938e 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.test.ts @@ -6,10 +6,8 @@ */ import { KueryNode } from '@kbn/es-query'; -import { - retryIfBulkEditConflicts, - RetryForConflictsAttempts, -} from './retry_if_bulk_edit_conflicts'; +import { retryIfBulkEditConflicts } from './retry_if_bulk_edit_conflicts'; +import { RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; import { loggingSystemMock } from '@kbn/core/server/mocks'; const mockFilter: KueryNode = { @@ -112,11 +110,11 @@ describe('retryIfBulkEditConflicts', () => { ).rejects.toThrowError('Test failure'); }); - test(`should return conflict errors when number of retries exceeds ${RetryForConflictsAttempts}`, async () => { + test(`should return conflict errors when number of retries exceeds ${RETRY_IF_CONFLICTS_ATTEMPTS}`, async () => { const result = await retryIfBulkEditConflicts( mockLogger, mockOperationName, - getOperationConflictsTimes(RetryForConflictsAttempts + 1), + getOperationConflictsTimes(RETRY_IF_CONFLICTS_ATTEMPTS + 1), mockFilter ); @@ -132,7 +130,7 @@ describe('retryIfBulkEditConflicts', () => { expect(mockLogger.warn).toBeCalledWith(`${mockOperationName} conflicts, exceeded retries`); }); - for (let i = 1; i <= RetryForConflictsAttempts; i++) { + for (let i = 1; i <= RETRY_IF_CONFLICTS_ATTEMPTS; i++) { test(`should work when operation conflicts ${i} times`, async () => { const result = await retryIfBulkEditConflicts( mockLogger, diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts index 9e1e60acb768f..550e13a6bffe5 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts @@ -12,15 +12,7 @@ import { Logger, SavedObjectsBulkUpdateObject, SavedObjectsUpdateResponse } from import { convertRuleIdsToKueryNode } from '../../lib'; import { BulkEditError } from '../rules_client'; import { RawRule } from '../../types'; - -// number of times to retry when conflicts occur -export const RetryForConflictsAttempts = 2; - -// milliseconds to wait before retrying when conflicts occur -// note: we considered making this random, to help avoid a stampede, but -// with 1 retry it probably doesn't matter, and adding randomness could -// make it harder to diagnose issues -const RetryForConflictsDelay = 250; +import { waitBeforeNextRetry, RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; // max number of failed SO ids in one retry filter const MaxIdsNumberInRetryFilter = 1000; @@ -57,7 +49,7 @@ export const retryIfBulkEditConflicts = async ( name: string, bulkEditOperation: BulkEditOperation, filter: KueryNode | null, - retries: number = RetryForConflictsAttempts, + retries: number = RETRY_IF_CONFLICTS_ATTEMPTS, accApiKeysToInvalidate: string[] = [], accResults: Array> = [], accErrors: BulkEditError[] = [] @@ -154,13 +146,3 @@ export const retryIfBulkEditConflicts = async ( throw err; } }; - -// exponential delay before retry with adding random delay -async function waitBeforeNextRetry(retries: number): Promise { - const exponentialDelayMultiplier = 1 + (RetryForConflictsAttempts - retries) ** 2; - const randomDelayMs = Math.floor(Math.random() * 100); - - await new Promise((resolve) => - setTimeout(resolve, RetryForConflictsDelay * exponentialDelayMultiplier + randomDelayMs) - ); -} diff --git a/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.test.ts new file mode 100644 index 0000000000000..2fd74a7e08a7c --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + getExponentialDelayMultiplier, + randomDelayMs, + RETRY_IF_CONFLICTS_DELAY, + RETRY_IF_CONFLICTS_ATTEMPTS, + waitBeforeNextRetry, +} from './wait_before_next_retry'; + +describe('waitBeforeNextRetry', () => { + const randomDelayPart = 0.1; + + beforeEach(() => { + jest.spyOn(global.Math, 'random').mockReturnValue(randomDelayPart); + jest.spyOn(window, 'setTimeout'); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + + for (let i = 1; i <= RETRY_IF_CONFLICTS_ATTEMPTS; i++) { + it(`should set timout for ${i} tries`, async () => { + await waitBeforeNextRetry(i); + expect(setTimeout).toBeCalledTimes(1); + expect(setTimeout).toHaveBeenCalledWith( + expect.any(Function), + RETRY_IF_CONFLICTS_DELAY * getExponentialDelayMultiplier(i) + randomDelayMs + ); + }); + } +}); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.ts b/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.ts new file mode 100644 index 0000000000000..f836de26c4188 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/wait_before_next_retry.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. + */ + +export const RETRY_IF_CONFLICTS_ATTEMPTS = 2; + +// milliseconds to wait before retrying when conflicts occur +// note: we considered making this random, to help avoid a stampede, but +// with 1 retry it probably doesn't matter, and adding randomness could +// make it harder to diagnose issues +export const RETRY_IF_CONFLICTS_DELAY = 250; + +export const randomDelayMs = Math.floor(Math.random() * 100); +export const getExponentialDelayMultiplier = (retries: number) => + 1 + (RETRY_IF_CONFLICTS_ATTEMPTS - retries) ** 2; + +/** + * exponential delay before retry with adding random delay + */ +export const waitBeforeNextRetry = async (retries: number): Promise => { + const exponentialDelayMultiplier = getExponentialDelayMultiplier(retries); + + await new Promise((resolve) => + setTimeout(resolve, RETRY_IF_CONFLICTS_DELAY * exponentialDelayMultiplier + randomDelayMs) + ); +}; diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index d08f12f054a50..777cf340b53e7 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -33,6 +33,7 @@ import { SavedObjectsUtils, SavedObjectAttributes, SavedObjectsBulkUpdateObject, + SavedObjectsBulkDeleteObject, SavedObjectsUpdateResponse, } from '@kbn/core/server'; import { ActionsClient, ActionsAuthorization } from '@kbn/actions-plugin/server'; @@ -104,6 +105,7 @@ import { mapSortField, validateOperationOnAttributes, retryIfBulkEditConflicts, + retryIfBulkDeleteConflicts, applyBulkEditOperation, buildKueryNodeFilter, } from './lib'; @@ -178,7 +180,7 @@ export interface RuleAggregation { }; } -export interface RuleBulkEditAggregation { +export interface RuleBulkOperationAggregation { alertTypeId: { buckets: Array<{ key: string[]; @@ -297,6 +299,16 @@ export type BulkEditOptions = | BulkEditOptionsFilter | BulkEditOptionsIds; +export interface BulkDeleteOptionsFilter { + filter?: string | KueryNode; +} + +export interface BulkDeleteOptionsIds { + ids?: string[]; +} + +export type BulkDeleteOptions = BulkDeleteOptionsFilter | BulkDeleteOptionsIds; + export interface BulkEditError { message: string; rule: { @@ -305,6 +317,15 @@ export interface BulkEditError { }; } +export interface BulkDeleteError { + message: string; + status: number; + rule: { + id: string; + name: string; + }; +} + export interface AggregateOptions extends IndexType { search?: string; defaultSearchOperator?: 'AND' | 'OR'; @@ -433,7 +454,7 @@ const extractedSavedObjectParamReferenceNamePrefix = 'param:'; // NOTE: Changing this prefix will require a migration to update the prefix in all existing `rule` saved objects const preconfiguredConnectorActionRefPrefix = 'preconfigured:'; -const MAX_RULES_NUMBER_FOR_BULK_EDIT = 10000; +const MAX_RULES_NUMBER_FOR_BULK_OPERATION = 10000; const API_KEY_GENERATE_CONCURRENCY = 50; const RULE_TYPE_CHECKS_CONCURRENCY = 50; @@ -1695,6 +1716,212 @@ export class RulesClient { ); } + private getAuthorizationFilter = async () => { + try { + const authorizationTuple = await this.authorization.getFindAuthorizationFilter( + AlertingAuthorizationEntity.Rule, + alertingAuthorizationFilterOpts + ); + return authorizationTuple.filter; + } catch (error) { + this.auditLogger?.log( + ruleAuditEvent({ + action: RuleAuditAction.DELETE, + error, + }) + ); + throw error; + } + }; + + public bulkDeleteRules = async (options: BulkDeleteOptions) => { + const filter = (options as BulkDeleteOptionsFilter).filter; + const ids = (options as BulkDeleteOptionsIds).ids; + + if (!ids && !filter) { + throw Boom.badRequest( + "Either 'ids' or 'filter' property in method's arguments should be provided" + ); + } + + if (ids?.length === 0) { + throw Boom.badRequest("'ids' property should not be an empty array"); + } + + if (ids && filter) { + throw Boom.badRequest( + "Both 'filter' and 'ids' are supplied. Define either 'ids' or 'filter' properties in method's arguments" + ); + } + + const kueryNodeFilter = ids ? convertRuleIdsToKueryNode(ids) : buildKueryNodeFilter(filter); + const authorizationFilter = await this.getAuthorizationFilter(); + + const kueryNodeFilterWithAuth = + authorizationFilter && kueryNodeFilter + ? nodeBuilder.and([kueryNodeFilter, authorizationFilter as KueryNode]) + : kueryNodeFilter; + + const { aggregations, total } = await this.unsecuredSavedObjectsClient.find< + RawRule, + RuleBulkOperationAggregation + >({ + filter: kueryNodeFilterWithAuth, + page: 1, + perPage: 0, + type: 'alert', + aggs: { + alertTypeId: { + multi_terms: { + terms: [ + { field: 'alert.attributes.alertTypeId' }, + { field: 'alert.attributes.consumer' }, + ], + }, + }, + }, + }); + + if (total > MAX_RULES_NUMBER_FOR_BULK_OPERATION) { + throw Boom.badRequest( + `More than ${MAX_RULES_NUMBER_FOR_BULK_OPERATION} rules matched for bulk delete` + ); + } + + const buckets = aggregations?.alertTypeId.buckets; + + if (buckets === undefined || buckets?.length === 0) { + throw Boom.badRequest('No rules found for bulk delete'); + } + + await pMap( + buckets, + async ({ key: [ruleType, consumer] }) => { + this.ruleTypeRegistry.ensureRuleTypeEnabled(ruleType); + try { + await this.authorization.ensureAuthorized({ + ruleTypeId: ruleType, + consumer, + operation: WriteOperations.BulkDelete, + entity: AlertingAuthorizationEntity.Rule, + }); + } catch (error) { + this.auditLogger?.log( + ruleAuditEvent({ + action: RuleAuditAction.DELETE, + error, + }) + ); + throw error; + } + }, + { concurrency: RULE_TYPE_CHECKS_CONCURRENCY } + ); + + const { apiKeysToInvalidate, errors, taskIdsToDelete } = await retryIfBulkDeleteConflicts( + this.logger, + (filterKueryNode: KueryNode | null) => this.bulkDeleteWithOCC({ filter: filterKueryNode }), + kueryNodeFilterWithAuth + ); + + const taskIdsFailedToBeDeleted: string[] = []; + if (taskIdsToDelete.length > 0) { + try { + const resultFromDeletingTasks = await this.taskManager.bulkRemoveIfExist(taskIdsToDelete); + resultFromDeletingTasks?.statuses.forEach((status) => { + if (!status.success) { + taskIdsFailedToBeDeleted.push(status.id); + } + }); + this.logger.debug( + `Successfully deleted schedules for underlying tasks: ${taskIdsToDelete + .filter((id) => taskIdsFailedToBeDeleted.includes(id)) + .join(', ')}` + ); + } catch (error) { + this.logger.error( + `Failure to delete schedules for underlying tasks: ${taskIdsToDelete.join( + ', ' + )}. TaskManager bulkRemoveIfExist failed with Error: ${error.message}` + ); + } + } + + await bulkMarkApiKeysForInvalidation( + { apiKeys: apiKeysToInvalidate }, + this.logger, + this.unsecuredSavedObjectsClient + ); + + return { errors, total, taskIdsFailedToBeDeleted }; + }; + + private bulkDeleteWithOCC = async ({ filter }: { filter: KueryNode | null }) => { + const rulesFinder = + await this.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + { + filter, + type: 'alert', + perPage: 100, + ...(this.namespace ? { namespaces: [this.namespace] } : undefined), + } + ); + + const rules: SavedObjectsBulkDeleteObject[] = []; + const apiKeysToInvalidate: string[] = []; + const taskIdsToDelete: string[] = []; + const errors: BulkDeleteError[] = []; + const apiKeyToRuleIdMapping: Record = {}; + const taskIdToRuleIdMapping: Record = {}; + const ruleNameToRuleIdMapping: Record = {}; + + for await (const response of rulesFinder.find()) { + for (const rule of response.saved_objects) { + if (rule.attributes.apiKey) { + apiKeyToRuleIdMapping[rule.id] = rule.attributes.apiKey; + } + if (rule.attributes.name) { + ruleNameToRuleIdMapping[rule.id] = rule.attributes.name; + } + if (rule.attributes.scheduledTaskId) { + taskIdToRuleIdMapping[rule.id] = rule.attributes.scheduledTaskId; + } + rules.push(rule); + + this.auditLogger?.log( + ruleAuditEvent({ + action: RuleAuditAction.DELETE, + outcome: 'unknown', + savedObject: { type: 'alert', id: rule.id }, + }) + ); + } + } + + const result = await this.unsecuredSavedObjectsClient.bulkDelete(rules); + + result.statuses.forEach((status) => { + if (status.error === undefined) { + if (apiKeyToRuleIdMapping[status.id]) { + apiKeysToInvalidate.push(apiKeyToRuleIdMapping[status.id]); + } + if (taskIdToRuleIdMapping[status.id]) { + taskIdsToDelete.push(taskIdToRuleIdMapping[status.id]); + } + } else { + errors.push({ + message: status.error.message ?? 'n/a', + status: status.error.statusCode, + rule: { + id: status.id, + name: ruleNameToRuleIdMapping[status.id] ?? 'n/a', + }, + }); + } + }); + return { apiKeysToInvalidate, errors, taskIdsToDelete }; + }; + public async bulkEdit( options: BulkEditOptions ): Promise<{ @@ -1737,7 +1964,7 @@ export class RulesClient { const { aggregations, total } = await this.unsecuredSavedObjectsClient.find< RawRule, - RuleBulkEditAggregation + RuleBulkOperationAggregation >({ filter: qNodeFilterWithAuth, page: 1, @@ -1755,9 +1982,9 @@ export class RulesClient { }, }); - if (total > MAX_RULES_NUMBER_FOR_BULK_EDIT) { + if (total > MAX_RULES_NUMBER_FOR_BULK_OPERATION) { throw Boom.badRequest( - `More than ${MAX_RULES_NUMBER_FOR_BULK_EDIT} rules matched for bulk edit` + `More than ${MAX_RULES_NUMBER_FOR_BULK_OPERATION} rules matched for bulk edit` ); } const buckets = aggregations?.alertTypeId.buckets; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts new file mode 100644 index 0000000000000..5e0a71edcae51 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts @@ -0,0 +1,492 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RulesClient, ConstructorOptions } from '../rules_client'; +import { savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; +import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; +import { RecoveredActionGroup } from '../../../common'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; +import { AlertingAuthorization } from '../../authorization/alerting_authorization'; +import { ActionsAuthorization } from '@kbn/actions-plugin/server'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { getBeforeSetup, setGlobalDate } from './lib'; +import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; +import { loggerMock } from '@kbn/logging-mocks'; + +jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({ + bulkMarkApiKeysForInvalidation: jest.fn(), +})); + +const taskManager = taskManagerMock.createStart(); +const ruleTypeRegistry = ruleTypeRegistryMock.create(); +const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); +const encryptedSavedObjects = encryptedSavedObjectsMock.createClient(); +const authorization = alertingAuthorizationMock.create(); +const actionsAuthorization = actionsAuthorizationMock.create(); +const auditLogger = auditLoggerMock.create(); +const logger = loggerMock.create(); + +const kibanaVersion = 'v8.2.0'; +const createAPIKeyMock = jest.fn(); +const rulesClientParams: jest.Mocked = { + taskManager, + ruleTypeRegistry, + unsecuredSavedObjectsClient, + authorization: authorization as unknown as AlertingAuthorization, + actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization, + spaceId: 'default', + namespace: 'default', + getUserName: jest.fn(), + createAPIKey: createAPIKeyMock, + logger, + encryptedSavedObjectsClient: encryptedSavedObjects, + getActionsClient: jest.fn(), + getEventLogClient: jest.fn(), + kibanaVersion, + auditLogger, + minimumScheduleInterval: { value: '1m', enforce: false }, +}; + +beforeEach(() => { + getBeforeSetup(rulesClientParams, taskManager, ruleTypeRegistry); + (auditLogger.log as jest.Mock).mockClear(); +}); + +setGlobalDate(); + +describe('bulkDelete', () => { + let rulesClient: RulesClient; + const existingRule = { + id: 'id1', + type: 'alert', + attributes: {}, + references: [], + version: '123', + }; + const existingDecryptedRule1 = { + ...existingRule, + attributes: { + ...existingRule.attributes, + scheduledTaskId: 'taskId1', + apiKey: Buffer.from('123:abc').toString('base64'), + }, + }; + const existingDecryptedRule2 = { + ...existingRule, + id: 'id2', + attributes: { + ...existingRule.attributes, + scheduledTaskId: 'taskId2', + apiKey: Buffer.from('321:abc').toString('base64'), + }, + }; + + const mockCreatePointInTimeFinderAsInternalUser = ( + response = { saved_objects: [existingDecryptedRule1, existingDecryptedRule2] } + ) => { + encryptedSavedObjects.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockResolvedValue({ + close: jest.fn(), + find: function* asyncGenerator() { + yield response; + }, + }); + }; + + beforeEach(async () => { + rulesClient = new RulesClient(rulesClientParams); + authorization.getFindAuthorizationFilter.mockResolvedValue({ + ensureRuleTypeIsAuthorized() {}, + }); + + unsecuredSavedObjectsClient.find.mockResolvedValue({ + aggregations: { + alertTypeId: { + buckets: [{ key: ['myType', 'myApp'], key_as_string: 'myType|myApp', doc_count: 2 }], + }, + }, + saved_objects: [], + per_page: 0, + page: 0, + total: 2, + }); + + ruleTypeRegistry.get.mockReturnValue({ + id: 'myType', + name: 'Test', + actionGroups: [ + { id: 'default', name: 'Default' }, + { id: 'custom', name: 'Not the Default' }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, + async executor() {}, + producer: 'alerts', + }); + }); + + test('should try to delete rules, one successful and one with 500 error', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { + id: 'id2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 500, + }, + }, + ], + }); + + const result = await rulesClient.bulkDeleteRules({ filter: 'fake_filter' }); + + expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledTimes(1); + expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledWith([ + existingDecryptedRule1, + existingDecryptedRule2, + ]); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['taskId1']); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( + { apiKeys: ['MTIzOmFiYw=='] }, + expect.anything(), + expect.anything() + ); + expect(result).toStrictEqual({ + errors: [{ message: 'UPS', rule: { id: 'id2', name: 'n/a' }, status: 500 }], + total: 2, + taskIdsFailedToBeDeleted: [], + }); + }); + + test('should try to delete rules, one successful and one with 409 error, which will not be deleted with retry', async () => { + unsecuredSavedObjectsClient.bulkDelete + .mockResolvedValueOnce({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { + id: 'id2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 409, + }, + }, + ], + }) + .mockResolvedValueOnce({ + statuses: [ + { + id: 'id2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 409, + }, + }, + ], + }) + .mockResolvedValueOnce({ + statuses: [ + { + id: 'id2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 409, + }, + }, + ], + }); + + encryptedSavedObjects.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule1, existingDecryptedRule2] }; + }, + }) + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule2] }; + }, + }) + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule2] }; + }, + }); + + const result = await rulesClient.bulkDeleteRules({ ids: ['id1', 'id2'] }); + + expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledTimes(3); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['taskId1']); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( + { apiKeys: ['MTIzOmFiYw=='] }, + expect.anything(), + expect.anything() + ); + expect(result).toStrictEqual({ + errors: [{ message: 'UPS', rule: { id: 'id2', name: 'n/a' }, status: 409 }], + total: 2, + taskIdsFailedToBeDeleted: [], + }); + }); + + test('should try to delete rules, one successful and one with 409 error, which successfully will be deleted with retry', async () => { + unsecuredSavedObjectsClient.bulkDelete + .mockResolvedValueOnce({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { + id: 'id2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 409, + }, + }, + ], + }) + .mockResolvedValueOnce({ + statuses: [ + { + id: 'id2', + type: 'alert', + success: true, + }, + ], + }); + + encryptedSavedObjects.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule1, existingDecryptedRule2] }; + }, + }) + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule2] }; + }, + }) + .mockResolvedValueOnce({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [existingDecryptedRule2] }; + }, + }); + + const result = await rulesClient.bulkDeleteRules({ ids: ['id1', 'id2'] }); + + expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledTimes(2); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['taskId1', 'taskId2']); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); + expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( + { apiKeys: ['MTIzOmFiYw==', 'MzIxOmFiYw=='] }, + expect.anything(), + expect.anything() + ); + expect(result).toStrictEqual({ + errors: [], + total: 2, + taskIdsFailedToBeDeleted: [], + }); + }); + + test('should thow an error if number of matched rules greater than 10,000', async () => { + unsecuredSavedObjectsClient.find.mockResolvedValue({ + aggregations: { + alertTypeId: { + buckets: [{ key: ['myType', 'myApp'], key_as_string: 'myType|myApp', doc_count: 2 }], + }, + }, + saved_objects: [], + per_page: 0, + page: 0, + total: 10001, + }); + + await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrow( + 'More than 10000 rules matched for bulk delete' + ); + }); + + test('should throw an error if we do not get buckets', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + unsecuredSavedObjectsClient.find.mockResolvedValue({ + aggregations: { + alertTypeId: {}, + }, + saved_objects: [], + per_page: 0, + page: 0, + total: 2, + }); + + await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrow( + 'No rules found for bulk delete' + ); + }); + + describe('taskManager', () => { + test('should return task id if deleting task failed', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { id: 'id2', type: 'alert', success: true }, + ], + }); + taskManager.bulkRemoveIfExist.mockImplementation(async () => ({ + statuses: [ + { + id: 'taskId1', + type: 'alert', + success: true, + }, + { + id: 'taskId2', + type: 'alert', + success: false, + error: { + error: '', + message: 'UPS', + statusCode: 500, + }, + }, + ], + })); + + const result = await rulesClient.bulkDeleteRules({ filter: 'fake_filter' }); + + expect(logger.debug).toBeCalledTimes(1); + expect(logger.debug).toBeCalledWith( + 'Successfully deleted schedules for underlying tasks: taskId2' + ); + expect(result).toStrictEqual({ + errors: [], + total: 2, + taskIdsFailedToBeDeleted: ['taskId2'], + }); + }); + + test('should not throw an error if taskManager throw an error', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { id: 'id2', type: 'alert', success: true }, + ], + }); + taskManager.bulkRemoveIfExist.mockImplementation(() => { + throw new Error('UPS'); + }); + + const result = await rulesClient.bulkDeleteRules({ filter: 'fake_filter' }); + + expect(logger.error).toBeCalledTimes(1); + expect(logger.error).toBeCalledWith( + 'Failure to delete schedules for underlying tasks: taskId1, taskId2. TaskManager bulkRemoveIfExist failed with Error: UPS' + ); + expect(result).toStrictEqual({ + errors: [], + taskIdsFailedToBeDeleted: [], + total: 2, + }); + }); + }); + + describe('auditLogger', () => { + jest.spyOn(auditLogger, 'log').mockImplementation(); + + test('logs audit event when deleting rules', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [ + { id: 'id1', type: 'alert', success: true }, + { id: 'id2', type: 'alert', success: true }, + ], + }); + + await rulesClient.bulkDeleteRules({ filter: 'fake_filter' }); + + expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_delete'); + expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('unknown'); + expect(auditLogger.log.mock.calls[0][0]?.kibana).toEqual({ + saved_object: { id: 'id1', type: 'alert' }, + }); + expect(auditLogger.log.mock.calls[1][0]?.event?.action).toEqual('rule_delete'); + expect(auditLogger.log.mock.calls[1][0]?.event?.outcome).toEqual('unknown'); + expect(auditLogger.log.mock.calls[1][0]?.kibana).toEqual({ + saved_object: { id: 'id2', type: 'alert' }, + }); + }); + + test('logs audit event when authentication failed', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + authorization.ensureAuthorized.mockImplementation(() => { + throw new Error('Unauthorized'); + }); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [{ id: 'id1', type: 'alert', success: true }], + }); + + await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrowError( + 'Unauthorized' + ); + + expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_delete'); + expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('failure'); + }); + + test('logs audit event when getting an authorization filter failed', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + authorization.getFindAuthorizationFilter.mockImplementation(() => { + throw new Error('Error'); + }); + unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ + statuses: [{ id: 'id1', type: 'alert', success: true }], + }); + + await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrowError( + 'Error' + ); + + expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_delete'); + expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('failure'); + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts index 37eccba1d0d56..6a1e84b38d039 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts @@ -51,6 +51,9 @@ export function getBeforeSetup( rulesClientParams.createAPIKey.mockResolvedValue({ apiKeysEnabled: false }); rulesClientParams.getUserName.mockResolvedValue('elastic'); taskManager.runSoon.mockResolvedValue({ id: '' }); + taskManager.bulkRemoveIfExist.mockResolvedValue({ + statuses: [{ id: 'taskId', type: 'alert', success: true }], + }); const actionsClient = actionsClientMock.create(); actionsClient.getBulk.mockResolvedValueOnce([ diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 95c36d24aad5b..8a1ae899ddd3b 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -75,6 +75,8 @@ exports[`Error FAAS_DURATION 1`] = `undefined`; exports[`Error FAAS_ID 1`] = `undefined`; +exports[`Error FAAS_NAME 1`] = `undefined`; + exports[`Error FAAS_TRIGGER_TYPE 1`] = `undefined`; exports[`Error HOST 1`] = ` @@ -330,6 +332,8 @@ exports[`Span FAAS_DURATION 1`] = `undefined`; exports[`Span FAAS_ID 1`] = `undefined`; +exports[`Span FAAS_NAME 1`] = `undefined`; + exports[`Span FAAS_TRIGGER_TYPE 1`] = `undefined`; exports[`Span HOST 1`] = `undefined`; @@ -581,6 +585,8 @@ exports[`Transaction FAAS_DURATION 1`] = `undefined`; exports[`Transaction FAAS_ID 1`] = `undefined`; +exports[`Transaction FAAS_NAME 1`] = `undefined`; + exports[`Transaction FAAS_TRIGGER_TYPE 1`] = `undefined`; exports[`Transaction HOST 1`] = ` diff --git a/x-pack/plugins/apm/common/agent_configuration/runtime_types/trace_continuation_strategy_rt.ts b/x-pack/plugins/apm/common/agent_configuration/runtime_types/trace_continuation_strategy_rt.ts new file mode 100644 index 0000000000000..13eed0a78f966 --- /dev/null +++ b/x-pack/plugins/apm/common/agent_configuration/runtime_types/trace_continuation_strategy_rt.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const traceContinuationStrategyRt = t.union([ + t.literal('continue'), + t.literal('restart'), + t.literal('restart_external'), +]); diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap index fc42af5ff7724..a4bc508856b45 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap @@ -47,21 +47,57 @@ Array [ "type": "select", "validationName": "(\\"off\\" | \\"errors\\" | \\"transactions\\" | \\"all\\")", }, + Object { + "key": "capture_body_content_types", + "type": "text", + "validationName": "string", + }, Object { "key": "capture_headers", "type": "boolean", "validationName": "(\\"true\\" | \\"false\\")", }, + Object { + "key": "capture_jmx_metrics", + "type": "text", + "validationName": "string", + }, Object { "key": "circuit_breaker_enabled", "type": "boolean", "validationName": "(\\"true\\" | \\"false\\")", }, + Object { + "key": "dedot_custom_metrics", + "type": "boolean", + "validationName": "(\\"true\\" | \\"false\\")", + }, Object { "key": "enable_log_correlation", "type": "boolean", "validationName": "(\\"true\\" | \\"false\\")", }, + Object { + "key": "exit_span_min_duration", + "min": "0ms", + "type": "duration", + "units": Array [ + "ms", + "s", + "m", + ], + "validationName": "durationRt", + }, + Object { + "key": "ignore_exceptions", + "type": "text", + "validationName": "string", + }, + Object { + "key": "ignore_message_queues", + "type": "text", + "validationName": "string", + }, Object { "key": "log_level", "options": Array [ @@ -156,6 +192,33 @@ Array [ ], "validationName": "durationRt", }, + Object { + "key": "span_compression_enabled", + "type": "boolean", + "validationName": "(\\"true\\" | \\"false\\")", + }, + Object { + "key": "span_compression_exact_match_max_duration", + "min": "0ms", + "type": "duration", + "units": Array [ + "ms", + "s", + "m", + ], + "validationName": "durationRt", + }, + Object { + "key": "span_compression_same_kind_max_duration", + "min": "0ms", + "type": "duration", + "units": Array [ + "ms", + "s", + "m", + ], + "validationName": "durationRt", + }, Object { "key": "span_frames_min_duration", "min": "-1ms", @@ -205,11 +268,40 @@ Array [ "type": "float", "validationName": "floatRt", }, + Object { + "key": "trace_continuation_strategy", + "options": Array [ + Object { + "text": "continue", + "value": "continue", + }, + Object { + "text": "restart", + "value": "restart", + }, + Object { + "text": "restart_external", + "value": "restart_external", + }, + ], + "type": "select", + "validationName": "(\\"continue\\" | \\"restart\\" | \\"restart_external\\")", + }, + Object { + "key": "trace_methods", + "type": "text", + "validationName": "string", + }, Object { "key": "transaction_ignore_urls", "type": "text", "validationName": "string", }, + Object { + "key": "transaction_ignore_user_agents", + "type": "text", + "validationName": "string", + }, Object { "key": "transaction_max_spans", "max": undefined, @@ -217,10 +309,25 @@ Array [ "type": "integer", "validationName": "integerRt", }, + Object { + "key": "transaction_name_groups", + "type": "text", + "validationName": "string", + }, Object { "key": "transaction_sample_rate", "type": "float", "validationName": "floatRt", }, + Object { + "key": "unnest_exceptions", + "type": "text", + "validationName": "string", + }, + Object { + "key": "use_path_as_transaction_name", + "type": "boolean", + "validationName": "(\\"true\\" | \\"false\\")", + }, ] `; diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts index 0e565e1d88030..4e0f37fc76f3b 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/general_settings.ts @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n'; import { captureBodyRt } from '../runtime_types/capture_body_rt'; import { logLevelRt } from '../runtime_types/log_level_rt'; +import { traceContinuationStrategyRt } from '../runtime_types/trace_continuation_strategy_rt'; import { RawSettingDefinition } from './types'; export const generalSettings: RawSettingDefinition[] = [ @@ -72,6 +73,29 @@ export const generalSettings: RawSettingDefinition[] = [ excludeAgents: ['js-base', 'rum-js', 'php'], }, + { + key: 'capture_body_content_types', + type: 'text', + defaultValue: + 'application/x-www-form-urlencoded*, text/*, application/json*, application/xml*', + label: i18n.translate( + 'xpack.apm.agentConfig.captureBodyContentTypes.label', + { + defaultMessage: 'Capture Body Content Types', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.captureBodyContentTypes.description', + { + defaultMessage: + 'Configures which content types should be recorded.\n' + + '\n' + + 'The defaults end with a wildcard so that content types like `text/plain; charset=utf-8` are captured as well.', + } + ), + includeAgents: ['java'], + }, + // Capture headers { key: 'capture_headers', @@ -90,6 +114,67 @@ export const generalSettings: RawSettingDefinition[] = [ excludeAgents: ['js-base', 'rum-js', 'nodejs', 'php'], }, + { + key: 'dedot_custom_metrics', + type: 'boolean', + defaultValue: 'true', + label: i18n.translate('xpack.apm.agentConfig.dedotCustomMetrics.label', { + defaultMessage: 'Dedot custom metrics', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.dedotCustomMetrics.description', + { + defaultMessage: + 'Replaces dots with underscores in the metric names for custom metrics.\n' + + '\n' + + 'WARNING: Setting this to `false` can lead to mapping conflicts as dots indicate nesting in Elasticsearch.\n' + + 'An example of when a conflict happens is two metrics with the name `foo` and `foo.bar`.\n' + + 'The first metric maps `foo` to a number and the second metric maps `foo` as an object.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'exit_span_min_duration', + type: 'duration', + defaultValue: '0ms', + min: '0ms', + label: i18n.translate('xpack.apm.agentConfig.exitSpanMinDuration.label', { + defaultMessage: 'Exit span min duration', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.exitSpanMinDuration.description', + { + defaultMessage: + 'Exit spans are spans that represent a call to an external service, like a database. If such calls are very short, they are usually not relevant and can be ignored.\n' + + '\n' + + 'NOTE: If a span propagates distributed tracing ids, it will not be ignored, even if it is shorter than the configured threshold. This is to ensure that no broken traces are recorded.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'ignore_message_queues', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.ignoreMessageQueues.label', { + defaultMessage: 'Ignore message queues', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.ignoreMessageQueues.description', + { + defaultMessage: + 'Used to filter out specific messaging queues/topics from being traced. \n' + + '\n' + + 'This property should be set to an array containing one or more strings.\n' + + 'When set, sends-to and receives-from the specified queues/topic will be ignored.', + } + ), + includeAgents: ['java'], + }, + // LOG_LEVEL { key: 'log_level', @@ -147,6 +232,68 @@ export const generalSettings: RawSettingDefinition[] = [ includeAgents: ['java'], }, + { + key: 'span_compression_enabled', + type: 'boolean', + defaultValue: 'true', + label: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionEnabled.label', + { + defaultMessage: 'Span compression enabled', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionEnabled.description', + { + defaultMessage: + 'Setting this option to true will enable span compression feature.\n' + + 'Span compression reduces the collection, processing, and storage overhead, and removes clutter from the UI. The tradeoff is that some information such as DB statements of all the compressed spans will not be collected.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'span_compression_exact_match_max_duration', + type: 'duration', + defaultValue: '50ms', + min: '0ms', + label: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionExactMatchMaxDuration.label', + { + defaultMessage: 'Span compression exact match max duration', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionExactMatchMaxDuration.description', + { + defaultMessage: + 'Consecutive spans that are exact match and that are under this threshold will be compressed into a single composite span. This option does not apply to composite spans. This reduces the collection, processing, and storage overhead, and removes clutter from the UI. The tradeoff is that the DB statements of all the compressed spans will not be collected.', + } + ), + includeAgents: ['java'], + }, + { + key: 'span_compression_same_kind_max_duration', + type: 'duration', + defaultValue: '0ms', + min: '0ms', + label: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionSameKindMaxDuration.label', + { + defaultMessage: 'Span compression same kind max duration', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.spanCompressionSameKindMaxDuration.description', + { + defaultMessage: + 'Consecutive spans to the same destination that are under this threshold will be compressed into a single composite span. This option does not apply to composite spans. This reduces the collection, processing, and storage overhead, and removes clutter from the UI. The tradeoff is that the DB statements of all the compressed spans will not be collected.', + } + ), + includeAgents: ['java'], + }, + // SPAN_FRAMES_MIN_DURATION { key: 'span_frames_min_duration', @@ -184,6 +331,44 @@ export const generalSettings: RawSettingDefinition[] = [ includeAgents: ['java', 'dotnet', 'go'], }, + { + key: 'trace_continuation_strategy', + validation: traceContinuationStrategyRt, + type: 'select', + defaultValue: 'continue', + label: i18n.translate( + 'xpack.apm.agentConfig.traceContinuationStrategy.label', + { + defaultMessage: 'Trace continuation strategy', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.traceContinuationStrategy.description', + { + defaultMessage: + 'This option allows some control over how the APM agent handles W3C trace-context headers on incoming requests. By default, the `traceparent` and `tracestate` headers are used per W3C spec for distributed tracing. However, in certain cases it can be helpful to not use the incoming `traceparent` header. Some example use cases:\n' + + '\n' + + '* An Elastic-monitored service is receiving requests with `traceparent` headers from unmonitored services.\n' + + '* An Elastic-monitored service is publicly exposed, and does not want tracing data (trace-ids, sampling decisions) to possibly be spoofed by user requests.\n' + + '\n' + + 'Valid values are:\n' + + "* 'continue': The default behavior. An incoming `traceparent` value is used to continue the trace and determine the sampling decision.\n" + + "* 'restart': Always ignores the `traceparent` header of incoming requests. A new trace-id will be generated and the sampling decision will be made based on transaction_sample_rate. A span link will be made to the incoming `traceparent`.\n" + + "* 'restart_external': If an incoming request includes the `es` vendor flag in `tracestate`, then any `traceparent` will be considered internal and will be handled as described for 'continue' above. Otherwise, any `traceparent` is considered external and will be handled as described for 'restart' above.\n" + + '\n' + + 'Starting with Elastic Observability 8.2, span links are visible in trace views.\n' + + '\n' + + 'This option is case-insensitive.', + } + ), + options: [ + { text: 'continue', value: 'continue' }, + { text: 'restart', value: 'restart' }, + { text: 'restart_external', value: 'restart_external' }, + ], + includeAgents: ['java'], + }, + // Transaction max spans { key: 'transaction_max_spans', @@ -257,4 +442,76 @@ export const generalSettings: RawSettingDefinition[] = [ ), includeAgents: ['java', 'nodejs', 'python', 'dotnet', 'ruby', 'go'], }, + + { + key: 'transaction_ignore_user_agents', + type: 'text', + defaultValue: '', + label: i18n.translate( + 'xpack.apm.agentConfig.transactionIgnoreUserAgents.label', + { + defaultMessage: 'Transaction ignore user agents', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.transactionIgnoreUserAgents.description', + { + defaultMessage: + 'Used to restrict requests from certain User-Agents from being instrumented.\n' + + '\n' + + 'When an incoming HTTP request is detected,\n' + + 'the User-Agent from the request headers will be tested against each element in this list.\n' + + 'Example: `curl/*`, `*pingdom*`', + } + ), + includeAgents: ['java'], + }, + + { + key: 'use_path_as_transaction_name', + type: 'boolean', + defaultValue: 'false', + label: i18n.translate( + 'xpack.apm.agentConfig.usePathAsTransactionName.label', + { + defaultMessage: 'Use path as transaction name', + } + ), + description: i18n.translate( + 'xpack.apm.agentConfig.usePathAsTransactionName.description', + { + defaultMessage: + 'If set to `true`,\n' + + 'transaction names of unsupported or partially-supported frameworks will be in the form of `$method $path` instead of just `$method unknown route`.\n' + + '\n' + + 'WARNING: If your URLs contain path parameters like `/user/$userId`,\n' + + 'you should be very careful when enabling this flag,\n' + + 'as it can lead to an explosion of transaction groups.\n' + + 'Take a look at the `transaction_name_groups` option on how to mitigate this problem by grouping URLs together.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'transaction_name_groups', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.transactionNameGroups.label', { + defaultMessage: 'Transaction name groups', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.transactionNameGroups.description', + { + defaultMessage: + 'With this option,\n' + + 'you can group transaction names that contain dynamic parts with a wildcard expression.\n' + + 'For example,\n' + + 'the pattern `GET /user/*/cart` would consolidate transactions,\n' + + 'such as `GET /users/42/cart` and `GET /users/73/cart` into a single transaction name `GET /users/*/cart`,\n' + + 'hence reducing the transaction name cardinality.', + } + ), + includeAgents: ['java'], + }, ]; diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.test.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.test.ts index c9d33d37b6601..e41a3b6896ee8 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.test.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.test.ts @@ -43,134 +43,150 @@ describe('filterByAgent', () => { describe('options per agent', () => { it('go', () => { - expect(getSettingKeysForAgent('go')).toEqual([ - 'capture_body', - 'capture_headers', - 'log_level', - 'recording', - 'sanitize_field_names', - 'span_frames_min_duration', - 'stack_trace_limit', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('go')).toEqual( + expect.arrayContaining([ + 'capture_body', + 'capture_headers', + 'log_level', + 'recording', + 'sanitize_field_names', + 'span_frames_min_duration', + 'stack_trace_limit', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('java', () => { - expect(getSettingKeysForAgent('java')).toEqual([ - 'api_request_size', - 'api_request_time', - 'capture_body', - 'capture_headers', - 'circuit_breaker_enabled', - 'enable_log_correlation', - 'log_level', - 'profiling_inferred_spans_enabled', - 'profiling_inferred_spans_excluded_classes', - 'profiling_inferred_spans_included_classes', - 'profiling_inferred_spans_min_duration', - 'profiling_inferred_spans_sampling_interval', - 'recording', - 'sanitize_field_names', - 'server_timeout', - 'span_frames_min_duration', - 'stack_trace_limit', - 'stress_monitor_cpu_duration_threshold', - 'stress_monitor_gc_relief_threshold', - 'stress_monitor_gc_stress_threshold', - 'stress_monitor_system_cpu_relief_threshold', - 'stress_monitor_system_cpu_stress_threshold', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('java')).toEqual( + expect.arrayContaining([ + 'api_request_size', + 'api_request_time', + 'capture_body', + 'capture_headers', + 'circuit_breaker_enabled', + 'enable_log_correlation', + 'log_level', + 'profiling_inferred_spans_enabled', + 'profiling_inferred_spans_excluded_classes', + 'profiling_inferred_spans_included_classes', + 'profiling_inferred_spans_min_duration', + 'profiling_inferred_spans_sampling_interval', + 'recording', + 'sanitize_field_names', + 'server_timeout', + 'span_frames_min_duration', + 'stack_trace_limit', + 'stress_monitor_cpu_duration_threshold', + 'stress_monitor_gc_relief_threshold', + 'stress_monitor_gc_stress_threshold', + 'stress_monitor_system_cpu_relief_threshold', + 'stress_monitor_system_cpu_stress_threshold', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('js-base', () => { - expect(getSettingKeysForAgent('js-base')).toEqual([ - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('js-base')).toEqual( + expect.arrayContaining(['transaction_sample_rate']) + ); }); it('rum-js', () => { - expect(getSettingKeysForAgent('rum-js')).toEqual([ - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('rum-js')).toEqual( + expect.arrayContaining(['transaction_sample_rate']) + ); }); it('nodejs', () => { - expect(getSettingKeysForAgent('nodejs')).toEqual([ - 'capture_body', - 'log_level', - 'sanitize_field_names', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('nodejs')).toEqual( + expect.arrayContaining([ + 'capture_body', + 'log_level', + 'sanitize_field_names', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('python', () => { - expect(getSettingKeysForAgent('python')).toEqual([ - 'api_request_size', - 'api_request_time', - 'capture_body', - 'capture_headers', - 'log_level', - 'recording', - 'sanitize_field_names', - 'span_frames_min_duration', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('python')).toEqual( + expect.arrayContaining([ + 'api_request_size', + 'api_request_time', + 'capture_body', + 'capture_headers', + 'log_level', + 'recording', + 'sanitize_field_names', + 'span_frames_min_duration', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('dotnet', () => { - expect(getSettingKeysForAgent('dotnet')).toEqual([ - 'capture_body', - 'capture_headers', - 'log_level', - 'recording', - 'sanitize_field_names', - 'span_frames_min_duration', - 'stack_trace_limit', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('dotnet')).toEqual( + expect.arrayContaining([ + 'capture_body', + 'capture_headers', + 'log_level', + 'recording', + 'sanitize_field_names', + 'span_frames_min_duration', + 'stack_trace_limit', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('ruby', () => { - expect(getSettingKeysForAgent('ruby')).toEqual([ - 'api_request_size', - 'api_request_time', - 'capture_body', - 'capture_headers', - 'log_level', - 'recording', - 'sanitize_field_names', - 'span_frames_min_duration', - 'transaction_ignore_urls', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('ruby')).toEqual( + expect.arrayContaining([ + 'api_request_size', + 'api_request_time', + 'capture_body', + 'capture_headers', + 'log_level', + 'recording', + 'sanitize_field_names', + 'span_frames_min_duration', + 'transaction_ignore_urls', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('php', () => { - expect(getSettingKeysForAgent('php')).toEqual([ - 'log_level', - 'recording', - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent('php')).toEqual( + expect.arrayContaining([ + 'log_level', + 'recording', + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); it('"All" services (no agent name)', () => { - expect(getSettingKeysForAgent(undefined)).toEqual([ - 'transaction_max_spans', - 'transaction_sample_rate', - ]); + expect(getSettingKeysForAgent(undefined)).toEqual( + expect.arrayContaining([ + 'transaction_max_spans', + 'transaction_sample_rate', + ]) + ); }); }); }); diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts index dc4eb89cf7dec..694eef7885b31 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/java_settings.ts @@ -238,4 +238,95 @@ export const javaSettings: RawSettingDefinition[] = [ ), includeAgents: ['java'], }, + + { + key: 'capture_jmx_metrics', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.captureJmxMetrics.label', { + defaultMessage: 'Capture JMX metrics', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.captureJmxMetrics.description', + { + defaultMessage: + 'Report metrics from JMX to the APM Server\n' + + '\n' + + 'Can contain multiple comma separated JMX metric definitions:\n' + + '\n' + + '`object_name[] attribute[:metric_name=]`\n' + + '\n' + + 'See the Java agent documentation for more details.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'ignore_exceptions', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.ignoreExceptions.label', { + defaultMessage: 'Ignore exceptions', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.ignoreExceptions.description', + { + defaultMessage: + 'A list of exceptions that should be ignored and not reported as errors.\n' + + 'This allows to ignore exceptions thrown in regular control flow that are not actual errors.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'trace_methods', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.traceMethods.label', { + defaultMessage: 'Trace methods', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.traceMethods.description', + { + defaultMessage: + 'A list of methods for which to create a transaction or span.\n' + + '\n' + + 'If you want to monitor a large number of methods,\n' + + 'use `profiling_inferred_spans_enabled`.\n' + + '\n' + + 'This works by instrumenting each matching method to include code that creates a span for the method.\n' + + 'While creating a span is quite cheap in terms of performance,\n' + + 'instrumenting a whole code base or a method which is executed in a tight loop leads to significant overhead.\n' + + '\n' + + 'NOTE: Only use wildcards if necessary.\n' + + 'The more methods you match the more overhead will be caused by the agent.\n' + + 'Also note that there is a maximum amount of spans per transaction `transaction_max_spans`.\n' + + '\n' + + 'See the Java agent documentation for more details.', + } + ), + includeAgents: ['java'], + }, + + { + key: 'unnest_exceptions', + type: 'text', + defaultValue: '', + label: i18n.translate('xpack.apm.agentConfig.unnestExceptions.label', { + defaultMessage: 'Unnest exceptions', + }), + description: i18n.translate( + 'xpack.apm.agentConfig.unnestExceptions.description', + { + defaultMessage: + 'When reporting exceptions,\n' + + 'un-nests the exceptions matching the wildcard pattern.\n' + + "This can come in handy for Spring's `org.springframework.web.util.NestedServletException`,\n" + + 'for example.', + } + ), + includeAgents: ['java'], + }, ]; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index f29bf3c607e86..bbd5755e3afb9 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -147,6 +147,7 @@ export const USER_AGENT_DEVICE = 'user_agent.device.name'; export const USER_AGENT_OS = 'user_agent.os.name'; export const FAAS_ID = 'faas.id'; +export const FAAS_NAME = 'faas.name'; export const FAAS_COLDSTART = 'faas.coldstart'; export const FAAS_TRIGGER_TYPE = 'faas.trigger.type'; export const FAAS_DURATION = 'faas.duration'; diff --git a/x-pack/plugins/apm/common/serverless.test.ts b/x-pack/plugins/apm/common/serverless.test.ts new file mode 100644 index 0000000000000..5473e9d735d86 --- /dev/null +++ b/x-pack/plugins/apm/common/serverless.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { getServerlessFunctionNameFromId } from './serverless'; + +describe('getServerlessFunctionNameFromId', () => { + it('returns serverlessId when regex does not match', () => { + expect(getServerlessFunctionNameFromId('foo')).toEqual('foo'); + }); + + it('returns correct serverless function name', () => { + expect( + getServerlessFunctionNameFromId( + 'arn:aws:lambda:us-west-2:123456789012:function:my-function' + ) + ).toEqual('my-function'); + expect( + getServerlessFunctionNameFromId( + 'arn:aws:lambda:us-west-2:123456789012:function:my:function' + ) + ).toEqual('my:function'); + }); +}); diff --git a/x-pack/plugins/apm/common/serverless.ts b/x-pack/plugins/apm/common/serverless.ts new file mode 100644 index 0000000000000..5e91cb04d868d --- /dev/null +++ b/x-pack/plugins/apm/common/serverless.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Gets the serverless function name from serverless id. + * Serverless id example: arn:aws:lambda:us-west-2:123456789012:function:my-function + * The function name is the last part after "function:" + */ +const serverlessIdRegex = /function:(.*)/; +export function getServerlessFunctionNameFromId(serverlessId: string) { + const match = serverlessIdRegex.exec(serverlessId); + return match ? match[1] : serverlessId; +} diff --git a/x-pack/plugins/apm/common/tutorial/instructions/apm_agent_instructions.ts b/x-pack/plugins/apm/common/tutorial/instructions/apm_agent_instructions.ts index b1c5fc79816ac..9406942f85179 100644 --- a/x-pack/plugins/apm/common/tutorial/instructions/apm_agent_instructions.ts +++ b/x-pack/plugins/apm/common/tutorial/instructions/apm_agent_instructions.ts @@ -519,10 +519,12 @@ export const createDotNetAgentInstructions = ( defaultMessage: 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ you can also configure the agent through environment variables. \n \ - See [the documentation]({documentationLink}) for advanced usage.', + See [the documentation]({documentationLink}) for advanced usage, including the [Profiler Auto instrumentation]({profilerLink}) quick start.', values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', + profilerLink: + '{config.docs.base_url}guide/en/apm/agent/dotnet/current/setup-auto-instrumentation.html#setup-auto-instrumentation', }, } ), 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 2efebecf25756..3fdeff2e406a8 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,6 +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('Daily data generation'); cy.contains('Traces per minute'); cy.contains('Number of services'); @@ -200,6 +202,7 @@ describe('Storage Explorer', () => { cy.contains('Service storage details'); cy.getByTestSubj('storageExplorerTimeseriesChart'); cy.getByTestSubj('serviceStorageDetailsTable'); + cy.getByTestSubj('storageExplorerIndicesStatsTable'); }); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts index 9e6e0189e636c..013296d815a58 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -21,7 +21,7 @@ Cypress.Commands.add('loginAsEditorUser', () => { Cypress.Commands.add('loginAsMonitorUser', () => { return cy.loginAs({ - username: ApmUsername.apmMonitorIndices, + username: ApmUsername.apmMonitorClusterAndIndices, password: 'changeme', }); }); diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx index 54d455519329c..00c768fc1abbf 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx @@ -108,7 +108,7 @@ function wrapper({ describe('useFailedTransactionsCorrelations', () => { beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); // Running all pending timers and switching to real timers using Jest afterEach(() => { diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.test.tsx b/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.test.tsx index b63327901a028..a09530960589c 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.test.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.test.tsx @@ -102,7 +102,7 @@ function wrapper({ describe('useLatencyCorrelations', () => { beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { jest.useRealTimers(); diff --git a/x-pack/plugins/apm/public/components/app/metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/index.tsx index 3149a13b940f8..0463df3778e87 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/index.tsx @@ -6,17 +6,30 @@ */ import React from 'react'; -import { isJavaAgentName, isJRubyAgent } from '../../../../common/agent_name'; +import { + isJavaAgentName, + isJRubyAgent, + isServerlessAgent, +} from '../../../../common/agent_name'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { ServerlessMetrics } from './serverless_metrics'; import { ServiceMetrics } from './service_metrics'; import { JvmMetricsOverview } from './jvm_metrics_overview'; export function Metrics() { const { agentName, runtimeName } = useApmServiceContext(); + const isServerless = isServerlessAgent(runtimeName); - if (isJavaAgentName(agentName) || isJRubyAgent(agentName, runtimeName)) { + if ( + !isServerless && + (isJavaAgentName(agentName) || isJRubyAgent(agentName, runtimeName)) + ) { return ; } + if (isServerless) { + return ; + } + return ; } diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/index.tsx new file mode 100644 index 0000000000000..439192503244f --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/index.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { ServerlessFunctions } from './serverless_functions'; +import { ServerlessSummary } from './serverless_summary'; +import { ServerlessActiveInstances } from './serverless_active_instances'; +import { ServerlessMetricsCharts } from './serverless_metrics_charts'; +import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; + +interface Props { + serverlessId?: string; +} + +export function ServerlessMetrics({ serverlessId }: Props) { + return ( + + + + + {!serverlessId && ( + + + + )} + + + + + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_active_instances.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_active_instances.tsx new file mode 100644 index 0000000000000..9c44d472c5b70 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_active_instances.tsx @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiBasicTableColumn, + EuiFlexGroup, + EuiFlexItem, + EuiInMemoryTable, + euiPaletteColorBlind, + EuiPanel, + EuiTitle, + PropertySort, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { + asDynamicBytes, + asInteger, + asMillisecondDuration, +} from '../../../../../common/utils/formatters'; +import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../hooks/use_time_range'; +import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { TimeseriesChart } from '../../../shared/charts/timeseries_chart'; +import { ListMetric } from '../../../shared/list_metric'; +import { ServerlessFunctionNameLink } from './serverless_function_name_link'; + +type ServerlessActiveInstances = + APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances'>; + +const palette = euiPaletteColorBlind({ rotations: 2 }); + +interface Props { + serverlessId?: string; +} + +export function ServerlessActiveInstances({ serverlessId }: Props) { + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/metrics'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { serviceName } = useApmServiceContext(); + + const { data = { activeInstances: [], timeseries: [] }, status } = useFetcher( + (callApmApi) => { + if (!start || !end) { + return undefined; + } + return callApmApi( + 'GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances', + { + params: { + path: { + serviceName, + }, + query: { + kuery, + environment, + start, + end, + serverlessId, + }, + }, + } + ); + }, + [kuery, environment, serviceName, start, end, serverlessId] + ); + + const isLoading = status === FETCH_STATUS.LOADING; + + const columns: Array< + EuiBasicTableColumn + > = [ + { + field: 'serverlessFunctionName', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.functionName', + { defaultMessage: 'Function name' } + ), + sortable: true, + truncateText: true, + render: (_, item) => { + return ( + + ); + }, + }, + { + field: 'activeInstanceName', + name: i18n.translate('xpack.apm.serverlessMetrics.activeInstances.name', { + defaultMessage: 'Name', + }), + sortable: true, + }, + { + field: 'serverlessDurationAvg', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.functionDuration', + { defaultMessage: 'Function duration' } + ), + sortable: true, + render: (_, { serverlessDurationAvg, timeseries }) => { + return ( + + ); + }, + }, + { + field: 'billedDurationAvg', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.billedDuration', + { defaultMessage: 'Billed duration' } + ), + sortable: true, + render: (_, { billedDurationAvg, timeseries }) => { + return ( + + ); + }, + }, + { + field: 'avgMemoryUsed', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.memoryUsageAvg', + { defaultMessage: 'Memory usage avg.' } + ), + sortable: true, + render: (_, { avgMemoryUsed }) => { + return asDynamicBytes(avgMemoryUsed); + }, + }, + { + field: 'memorySize', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.memorySize', + { defaultMessage: 'Memory size' } + ), + sortable: true, + render: (_, { memorySize }) => { + return asDynamicBytes(memorySize); + }, + }, + ]; + + const sorting = useMemo( + () => ({ + sort: { + field: 'serverlessDurationAvg', + direction: 'desc', + } as PropertySort, + }), + [] + ); + + const charts: Array> = useMemo( + () => [ + { + title: i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.title', + { defaultMessage: 'Active instances' } + ), + data: data.timeseries, + type: 'bar', + color: palette[2], + }, + ], + [data.timeseries] + ); + + return ( + + + + +

+ {i18n.translate( + 'xpack.apm.serverlessMetrics.activeInstances.title', + { defaultMessage: 'Active instances' } + )} +

+
+
+ + + + + + +
+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_function_name_link.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_function_name_link.tsx new file mode 100644 index 0000000000000..83fb9a5beee32 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_function_name_link.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiLink } from '@elastic/eui'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import React from 'react'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { truncate } from '../../../../utils/style'; + +const StyledLink = euiStyled(EuiLink)`${truncate('100%')};`; + +interface Props { + serverlessFunctionName: string; + serverlessId: string; +} + +export function ServerlessFunctionNameLink({ + serverlessFunctionName, + serverlessId, +}: Props) { + const { serviceName } = useApmServiceContext(); + const { query } = useApmParams('/services/{serviceName}/metrics'); + const { link } = useApmRouter(); + return ( + + {serverlessFunctionName} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_functions.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_functions.tsx new file mode 100644 index 0000000000000..11c2f9056b117 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_functions.tsx @@ -0,0 +1,178 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiBasicTableColumn, + EuiFlexGroup, + EuiFlexItem, + EuiInMemoryTable, + EuiPanel, + EuiTitle, + PropertySort, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { + asDynamicBytes, + asMillisecondDuration, +} from '../../../../../common/utils/formatters'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../hooks/use_time_range'; +import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { ServerlessFunctionNameLink } from './serverless_function_name_link'; + +type ServerlessFunctionOverview = + APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview'>['serverlessFunctionsOverview'][0]; + +export function ServerlessFunctions() { + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/metrics'); + + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { serviceName } = useApmServiceContext(); + + const { data = { serverlessFunctionsOverview: [] }, status } = useFetcher( + (callApmApi) => { + if (!start || !end) { + return undefined; + } + return callApmApi( + 'GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview', + { + params: { + path: { + serviceName, + }, + query: { + kuery, + environment, + start, + end, + }, + }, + } + ); + }, + [kuery, environment, serviceName, start, end] + ); + + const columns: Array> = [ + { + field: 'serverlessFunctionName', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.functionName', + { defaultMessage: 'Function name' } + ), + sortable: true, + truncateText: true, + render: (_, item) => { + return ( + + ); + }, + }, + { + field: 'serverlessDurationAvg', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.functionDuration', + { defaultMessage: 'Function duration' } + ), + sortable: true, + render: (_, { serverlessDurationAvg }) => { + return asMillisecondDuration(serverlessDurationAvg); + }, + }, + { + field: 'billedDurationAvg', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.billedDuration', + { defaultMessage: 'Billed duration' } + ), + sortable: true, + render: (_, { billedDurationAvg }) => { + return asMillisecondDuration(billedDurationAvg); + }, + }, + { + field: 'avgMemoryUsed', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.memoryUsageAvg', + { defaultMessage: 'Memory usage avg.' } + ), + sortable: true, + render: (_, { avgMemoryUsed }) => { + return asDynamicBytes(avgMemoryUsed); + }, + }, + { + field: 'memorySize', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.memorySize', + { defaultMessage: 'Memory size' } + ), + sortable: true, + render: (_, { memorySize }) => { + return asDynamicBytes(memorySize); + }, + }, + { + field: 'coldStartCount', + name: i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.coldStart', + { defaultMessage: 'Cold start' } + ), + sortable: true, + }, + ]; + + const isLoading = status === FETCH_STATUS.LOADING; + + const sorting = useMemo( + () => ({ + sort: { + field: 'serverlessDurationAvg', + direction: 'desc', + } as PropertySort, + }), + [] + ); + + return ( + + + + + + +

+ {i18n.translate( + 'xpack.apm.serverlessMetrics.serverlessFunctions.title', + { defaultMessage: 'Lambda functions' } + )} +

+
+
+
+
+ + + +
+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_metrics_charts.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_metrics_charts.tsx new file mode 100644 index 0000000000000..ca5ea070b995c --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_metrics_charts.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import { isEmpty, keyBy } from 'lodash'; +import React from 'react'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useFetcher } from '../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../hooks/use_time_range'; +import { MetricsChart } from '../../../shared/charts/metrics_chart'; + +interface Props { + serverlessId?: string; +} + +const INITIAL_STATE = { + firstLineCharts: [], + secondLineCharts: [], +}; + +export function ServerlessMetricsCharts({ serverlessId }: Props) { + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/metrics'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { serviceName } = useApmServiceContext(); + + const { data = INITIAL_STATE, status } = useFetcher( + (callApmApi) => { + if (!start || !end) { + return undefined; + } + return callApmApi( + 'GET /internal/apm/services/{serviceName}/metrics/serverless/charts', + { + params: { + path: { + serviceName, + }, + query: { + kuery, + environment, + start, + end, + serverlessId, + }, + }, + } + ).then((resp) => { + const chartsByKey = keyBy(resp.charts, 'key'); + if (isEmpty(chartsByKey)) { + return { firstLineCharts: [], secondLineCharts: [] }; + } + + return { + firstLineCharts: [ + chartsByKey.avg_duration, + chartsByKey.cold_start_duration, + chartsByKey.cold_start_count, + ], + secondLineCharts: [ + chartsByKey.compute_usage, + chartsByKey.memory_usage_chart, + ], + }; + }); + }, + [kuery, environment, serviceName, start, end, serverlessId] + ); + + return ( + + + + {data.firstLineCharts.map((chart) => ( + + + + + + ))} + + + + + {data.secondLineCharts.map((chart) => ( + + + + + + ))} + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx new file mode 100644 index 0000000000000..f6d93cb9cd809 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiPanel, + EuiSpacer, + EuiStat, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import styled from 'styled-components'; +import { + asMillisecondDuration, + asPercent, +} from '../../../../../common/utils/formatters'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useBreakpoints } from '../../../../hooks/use_breakpoints'; +import { useFetcher, FETCH_STATUS } from '../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../hooks/use_time_range'; + +interface Props { + serverlessId?: string; +} + +const CentralizedContainer = styled.div` + display: flex; + align-items: center; +`; + +const Border = styled.div` + height: 55px; + border-right: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; +`; + +function VerticalRule() { + return ( + + + + ); +} + +export function ServerlessSummary({ serverlessId }: Props) { + const breakpoints = useBreakpoints(); + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/metrics'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { serviceName } = useApmServiceContext(); + + const { data, status } = useFetcher( + (callApmApi) => { + if (!start || !end) { + return undefined; + } + return callApmApi( + 'GET /internal/apm/services/{serviceName}/metrics/serverless/summary', + { + params: { + path: { + serviceName, + }, + query: { + kuery, + environment, + start, + end, + serverlessId, + }, + }, + } + ); + }, + [kuery, environment, serviceName, start, end, serverlessId] + ); + + const showVerticalRule = !breakpoints.isSmall; + const isLoading = status === FETCH_STATUS.LOADING; + + return ( + + + + +

+ {i18n.translate('xpack.apm.serverlessMetrics.summary.title', { + defaultMessage: 'Summary', + })} +

+
+
+ + + {i18n.translate('xpack.apm.serverlessMetrics.summary.feedback', { + defaultMessage: 'Send feedback', + })} + + +
+ + + + + + {showVerticalRule && } + + + + + + + + + + {showVerticalRule && } + +
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx index 4adbb25c26d1e..13082d41f5970 100644 --- a/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx @@ -5,8 +5,21 @@ * 2.0. */ import React from 'react'; +import { isServerlessAgent } from '../../../../common/agent_name'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../hooks/use_apm_params'; +import { ServerlessMetricsDetails } from './serverless_metrics_details'; import { ServiceNodeMetrics } from './service_node_metrics'; export function MetricsDetails() { - return ; + const { + path: { id }, + } = useApmParams('/services/{serviceName}/metrics/{id}'); + const { runtimeName } = useApmServiceContext(); + + if (isServerlessAgent(runtimeName)) { + return ; + } + + return ; } diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/serverless_metrics_details/index.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/serverless_metrics_details/index.tsx new file mode 100644 index 0000000000000..7b80ed857134d --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/metrics_details/serverless_metrics_details/index.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { ServerlessMetrics } from '../../metrics/serverless_metrics'; +import { getServerlessFunctionNameFromId } from '../../../../../common/serverless'; +import { useBreadcrumb } from '../../../../context/breadcrumbs/use_breadcrumb'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { useApmParams } from '../../../../hooks/use_apm_params'; + +interface Props { + serverlessId: string; +} + +export function ServerlessMetricsDetails({ serverlessId }: Props) { + const apmRouter = useApmRouter(); + const { path, query } = useApmParams('/services/{serviceName}/metrics/{id}'); + + const serverlessFunctionName = useMemo( + () => getServerlessFunctionNameFromId(serverlessId), + [serverlessId] + ); + + useBreadcrumb( + () => ({ + title: serverlessFunctionName, + href: apmRouter.link('/services/{serviceName}/metrics/{id}', { + path, + query, + }), + }), + [apmRouter, path, query, serverlessFunctionName] + ); + + return ( + + + +

{serverlessFunctionName}

+
+
+ + + +
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.test.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.test.tsx index 9356cab2d1f9c..e8deea04a71e0 100644 --- a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.test.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.test.tsx @@ -16,7 +16,7 @@ describe('ServiceNodeMetrics', () => { expect(() => shallow( - + ) ).not.toThrowError(); diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx index cc0703c036780..b78542f291f72 100644 --- a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx @@ -46,15 +46,16 @@ const Truncate = euiStyled.span` ${truncate(unit * 12)} `; -export function ServiceNodeMetrics() { +interface Props { + serviceNodeName: string; +} + +export function ServiceNodeMetrics({ serviceNodeName }: Props) { const { agentName, serviceName } = useApmServiceContext(); const apmRouter = useApmRouter(); - const { - path: { id: serviceNodeName }, - query, - } = useApmParams('/services/{serviceName}/metrics/{id}'); + const { query } = useApmParams('/services/{serviceName}/metrics/{id}'); const { environment, kuery, rangeFrom, rangeTo } = query; 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 new file mode 100644 index 0000000000000..1736cd852a417 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/get_storage_explorer_links.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart } from '@kbn/core-lifecycle-browser'; + +export function getIndexManagementHref(core: CoreStart) { + return core.application.getUrlForApp('management', { + path: '/data/index_management/data_streams', + }); +} + +export function getStorageExplorerFeedbackHref() { + return 'https://ela.st/feedback-storage-explorer'; +} + +export function getKibanaAdvancedSettingsHref(core: CoreStart) { + return core.application.getUrlForApp('management', { + path: '/kibana/settings?query=category:(observability)', + }); +} diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx index 5b8c044d2276c..ef0c198000ddd 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx @@ -12,8 +12,14 @@ import { EuiSpacer, EuiEmptyPrompt, EuiLoadingSpinner, + EuiCallOut, + EuiLink, + EuiButton, + EuiPanel, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { IndexLifecyclePhaseSelect } from './index_lifecycle_phase_select'; import { ServicesTable } from './services_table'; import { SearchBar } from '../../shared/search_bar'; @@ -22,18 +28,51 @@ import { PermissionDenied } from './prompts/permission_denied'; import { useFetcher, FETCH_STATUS } from '../../../hooks/use_fetcher'; import { SummaryStats } from './summary_stats'; import { ApmEnvironmentFilter } from '../../shared/environment_filter'; +import { TipsAndResources } from './resources/tips_and_resources'; +import { useLocalStorage } from '../../../hooks/use_local_storage'; +import { getKibanaAdvancedSettingsHref } from './get_storage_explorer_links'; -const INITIAL_DATA = { hasPrivileges: false }; +type CalloutType = 'crossClusterSearch' | 'optimizePerformance'; + +const CALLOUT_DISMISS_INITIAL_STATE: Record = { + crossClusterSearch: false, + optimizePerformance: false, +}; + +const dismissButtonText = i18n.translate( + 'xpack.apm.storageExplorer.callout.dimissButton', + { + defaultMessage: 'Dismiss', + } +); export function StorageExplorer() { - const { data: { hasPrivileges } = INITIAL_DATA, status } = useFetcher( + const { core } = useApmPluginContext(); + + const [calloutDismissed, setCalloutDismissed] = useLocalStorage( + 'apm.storageExplorer.calloutDismissed', + CALLOUT_DISMISS_INITIAL_STATE + ); + + const { data: hasPrivilegesData, status: hasPrivilegesStatus } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/storage_explorer/privileges'); }, [] ); - const loading = status === FETCH_STATUS.LOADING; + const { data: isCrossClusterSearchData } = useFetcher( + (callApmApi) => { + if (!calloutDismissed.crossClusterSearch) { + return callApmApi( + 'GET /internal/apm/storage_explorer/is_cross_cluster_search' + ); + } + }, + [calloutDismissed] + ); + + const loading = hasPrivilegesStatus === FETCH_STATUS.LOADING; if (loading) { return ( @@ -51,7 +90,7 @@ export function StorageExplorer() { ); } - if (!hasPrivileges) { + if (!hasPrivilegesData?.hasPrivileges) { return ; } @@ -67,11 +106,94 @@ export function StorageExplorer() { + + {!calloutDismissed.optimizePerformance && ( + +

+ + {i18n.translate( + 'xpack.apm.storageExplorer.longLoadingTimeCalloutLink', + { + defaultMessage: 'Kibana advanced settings', + } + )} + + ), + }} + /> +

+ + setCalloutDismissed({ + ...calloutDismissed, + optimizePerformance: true, + }) + } + > + {dismissButtonText} + +
+ )} + + {!calloutDismissed.crossClusterSearch && + isCrossClusterSearchData?.isCrossClusterSearch && ( + <> + + +

+ {i18n.translate( + 'xpack.apm.storageExplorer.crossClusterSearchCalloutText', + { + defaultMessage: + 'While getting document count works with cross-cluster search, index statistics such as size are only displayed for data that are stored in this cluster.', + } + )} +

+ + setCalloutDismissed({ + ...calloutDismissed, + crossClusterSearch: true, + }) + } + > + {dismissButtonText} + +
+ + )} + + - + + + + + - + ); } 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 new file mode 100644 index 0000000000000..8de6d7d3e56d7 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/resources/tips_and_resources.tsx @@ -0,0 +1,203 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + EuiAccordion, + EuiPanel, + EuiFlexItem, + EuiTitle, + EuiButton, + EuiCard, + EuiIcon, + EuiListGroup, + EuiFlexGroup, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { + getIndexManagementHref, + getStorageExplorerFeedbackHref, +} from '../get_storage_explorer_links'; + +export function TipsAndResources() { + const router = useApmRouter(); + const { core } = useApmPluginContext(); + const { docLinks } = core; + + const { + query: { rangeFrom, rangeTo, environment, kuery, comparisonEnabled }, + } = useApmParams('/storage-explorer'); + + const cards = [ + { + icon: 'beaker', + title: i18n.translate( + 'xpack.apm.storageExplorer.resources.errorMessages.title', + { + defaultMessage: 'Reduce transactions', + } + ), + description: i18n.translate( + 'xpack.apm.storageExplorer.resources.errorMessages.description', + { + defaultMessage: + 'Configure a more aggressive transaction sampling policy. Transaction sampling lowers the amount of data ingested without negatively impacting the usefulness of that data.', + } + ), + href: docLinks.links.apm.transactionSampling, + }, + { + icon: 'visLine', + title: i18n.translate( + 'xpack.apm.storageExplorer.resources.compressedSpans.title', + { + defaultMessage: 'Reduce spans', + } + ), + description: i18n.translate( + 'xpack.apm.storageExplorer.resources.compressedSpans.description', + { + defaultMessage: + 'Enable span compression. Span compression saves on data and transfer costs by compressing multiple similar spans into a single span.', + } + ), + href: docLinks.links.apm.spanCompression, + }, + { + icon: 'indexEdit', + title: i18n.translate( + 'xpack.apm.storageExplorer.resources.samplingRate.title', + { + defaultMessage: 'Manage the index lifecycle', + } + ), + description: i18n.translate( + 'xpack.apm.storageExplorer.resources.samplingRate.description', + { + defaultMessage: + 'Customize your index lifecycle policies. Index lifecycle policies allow you to manage indices according to your performance, resiliency, and retention requirements.', + } + ), + href: docLinks.links.apm.indexLifecycleManagement, + }, + ]; + + const resourcesListItems = [ + { + label: i18n.translate( + 'xpack.apm.storageExplorer.resources.indexManagement', + { + defaultMessage: 'Index management', + } + ), + href: getIndexManagementHref(core), + iconType: 'indexEdit', + }, + { + label: i18n.translate( + 'xpack.apm.storageExplorer.resources.serviceInventory', + { + defaultMessage: 'Service inventory', + } + ), + href: router.link('/services', { + query: { + rangeFrom, + rangeTo, + environment, + comparisonEnabled, + kuery, + serviceGroup: '', + }, + }), + iconType: 'tableDensityExpanded', + }, + { + label: i18n.translate( + 'xpack.apm.storageExplorer.resources.documentation', + { + defaultMessage: 'Documentation', + } + ), + href: docLinks.links.apm.storageExplorer, + target: '_blank', + iconType: 'documentation', + }, + { + label: i18n.translate( + 'xpack.apm.storageExplorer.resources.sendFeedback', + { + defaultMessage: 'Send feedback', + } + ), + href: getStorageExplorerFeedbackHref(), + target: '_blank', + iconType: 'editorComment', + }, + ]; + + return ( + + +

+ {i18n.translate( + 'xpack.apm.storageExplorer.resources.accordionTitle', + { + defaultMessage: 'Tips and tricks', + } + )} +

+ + } + initialIsOpen + paddingSize="m" + > + + {cards.map(({ icon, title, description, href }) => ( + + } + title={title} + description={description} + footer={ + + {i18n.translate( + 'xpack.apm.storageExplorer.resources.learnMoreButton', + { + defaultMessage: 'Learn more', + } + )} + + } + /> + + ))} + + +

+ {i18n.translate('xpack.apm.storageExplorer.resources.title', { + defaultMessage: 'Resources', + })} +

+
+ +
+
+
+
+ ); +} 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 7f2dd2d8a096f..8fe102ea72961 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 @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useEffect, ReactNode } from 'react'; +import React, { useState, ReactNode } from 'react'; import { EuiInMemoryTable, EuiBasicTableColumn, @@ -14,9 +14,13 @@ import { RIGHT_ALIGNMENT, EuiToolTip, EuiIcon, + EuiProgress, + EuiPanel, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ValuesType } from 'utility-types'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { apmServiceInventoryOptimizedSorting } from '@kbn/observability-plugin/common'; +import { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent'; import { EnvironmentBadge } from '../../../shared/environment_badge'; import { asPercent } from '../../../../../common/utils/formatters'; import { ServiceLink } from '../../../shared/service_link'; @@ -27,14 +31,26 @@ import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plug import { asDynamicBytes } from '../../../../../common/utils/formatters'; import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; import { useApmParams } from '../../../../hooks/use_apm_params'; -import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { useProgressiveFetcher } from '../../../../hooks/use_progressive_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { SizeLabel } from './size_label'; -import type { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { joinByKey } from '../../../../../common/utils/join_by_key'; -type StorageExplorerItems = - APIReturnType<'GET /internal/apm/storage_explorer'>['serviceStatistics']; +interface StorageExplorerItem { + serviceName: string; + environments?: string[]; + size?: number; + agentName?: AgentName; + sampling?: number; +} + +enum StorageExplorerFieldName { + ServiceName = 'serviceName', + Environments = 'environments', + Sampling = 'sampling', + Size = 'size', +} export function ServicesTable() { const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState< @@ -76,7 +92,29 @@ export function ServicesTable() { setItemIdToExpandedRowMap(expandedRowMapValues); }; - const { data, status } = useProgressiveFetcher( + const useOptimizedSorting = + useKibana().services.uiSettings?.get( + apmServiceInventoryOptimizedSorting + ) || false; + + const sortedAndFilteredServicesFetch = useFetcher( + (callApmApi) => { + if (useOptimizedSorting) { + return callApmApi('GET /internal/apm/storage_explorer/get_services', { + params: { + query: { + environment, + kuery, + indexLifecyclePhase, + }, + }, + }); + } + }, + [environment, kuery, indexLifecyclePhase, useOptimizedSorting] + ); + + const serviceStatisticsFetch = useProgressiveFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/storage_explorer', { params: { @@ -93,165 +131,193 @@ export function ServicesTable() { [indexLifecyclePhase, start, end, environment, kuery] ); - useEffect(() => { - // Closes any open rows when fetching new items - setItemIdToExpandedRowMap({}); - }, [status]); + const serviceStatisticsItems = + serviceStatisticsFetch.data?.serviceStatistics ?? []; + const preloadedServices = sortedAndFilteredServicesFetch.data?.services || []; + + const initialSortField = useOptimizedSorting + ? StorageExplorerFieldName.ServiceName + : StorageExplorerFieldName.Size; - const loading = - status === FETCH_STATUS.NOT_INITIATED || status === FETCH_STATUS.LOADING; + const initialSortDirection = + initialSortField === StorageExplorerFieldName.ServiceName ? 'asc' : 'desc'; - const columns: Array>> = + const loading = serviceStatisticsFetch.status === FETCH_STATUS.LOADING; + + const items = joinByKey( [ - { - field: 'serviceName', - name: i18n.translate( - 'xpack.apm.storageExplorer.table.serviceColumnName', - { - defaultMessage: 'Service', - } - ), - sortable: true, - render: (_, { serviceName, agentName }) => { - const serviceLinkQuery = { - comparisonEnabled, - environment, - kuery, - rangeFrom, - rangeTo, - serviceGroup: '', - }; + ...(initialSortField === StorageExplorerFieldName.ServiceName + ? preloadedServices + : []), + ...serviceStatisticsItems, + ], + 'serviceName' + ); - return ( - - } - /> - ); - }, - }, - { - field: 'environment', - name: i18n.translate( - 'xpack.apm.storageExplorer.table.environmentColumnName', - { - defaultMessage: 'Environment', - } - ), - render: (_, { environments }) => ( - - ), - sortable: true, - }, + const columns: Array> = [ + { + field: 'serviceName', + name: i18n.translate( + 'xpack.apm.storageExplorer.table.serviceColumnName', + { + defaultMessage: 'Service', + } + ), + sortable: true, + render: (_, { serviceName, agentName }) => { + const serviceLinkQuery = { + comparisonEnabled, + environment, + kuery, + rangeFrom, + rangeTo, + serviceGroup: '', + }; - { - field: 'sampling', - name: ( - - <> - {i18n.translate( - 'xpack.apm.storageExplorer.table.samplingColumnName', - { - defaultMessage: 'Sample rate', - } - )}{' '} - - - - ), - render: (value: string) => asPercent(parseFloat(value), 1), - sortable: true, + } + /> + ); }, - { - field: 'size', - name: , - render: (_, { size }) => asDynamicBytes(size) || NOT_AVAILABLE_LABEL, - sortable: true, - }, - { - align: RIGHT_ALIGNMENT, - width: '40px', - isExpander: true, - name: ( - - - {i18n.translate('xpack.apm.storageExplorer.table.expandRow', { - defaultMessage: 'Expand row', - })} - - - ), - render: ({ serviceName }: { serviceName: string }) => { - return ( - toggleRowDetails(serviceName)} - aria-label={ - itemIdToExpandedRowMap[serviceName] - ? i18n.translate('xpack.apm.storageExplorer.table.collapse', { - defaultMessage: 'Collapse', - }) - : i18n.translate('xpack.apm.storageExplorer.table.expand', { - defaultMessage: 'Expand', - }) - } - iconType={ - itemIdToExpandedRowMap[serviceName] ? 'arrowUp' : 'arrowDown' + }, + { + field: 'environment', + name: i18n.translate( + 'xpack.apm.storageExplorer.table.environmentColumnName', + { + defaultMessage: 'Environment', + } + ), + render: (_, { environments }) => ( + + ), + sortable: true, + }, + + { + field: 'sampling', + name: ( + + <> + {i18n.translate( + 'xpack.apm.storageExplorer.table.samplingColumnName', + { + defaultMessage: 'Sample rate', } + )}{' '} + - ); - }, + + + ), + render: (value: string) => asPercent(parseFloat(value), 1), + sortable: true, + }, + { + field: 'size', + name: , + render: (_, { size }) => asDynamicBytes(size) || NOT_AVAILABLE_LABEL, + sortable: true, + }, + { + align: RIGHT_ALIGNMENT, + width: '40px', + isExpander: true, + name: ( + + + {i18n.translate('xpack.apm.storageExplorer.table.expandRow', { + defaultMessage: 'Expand row', + })} + + + ), + render: ({ serviceName }: { serviceName: string }) => { + return ( + toggleRowDetails(serviceName)} + aria-label={ + itemIdToExpandedRowMap[serviceName] + ? i18n.translate('xpack.apm.storageExplorer.table.collapse', { + defaultMessage: 'Collapse', + }) + : i18n.translate('xpack.apm.storageExplorer.table.expand', { + defaultMessage: 'Expand', + }) + } + iconType={ + itemIdToExpandedRowMap[serviceName] ? 'arrowUp' : 'arrowDown' + } + /> + ); }, - ]; + }, + ]; return ( - + + {loading && } + + ); } diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index_stats_per_service.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index_stats_per_service.tsx new file mode 100644 index 0000000000000..04505e85ef806 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index_stats_per_service.tsx @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiInMemoryTable, + EuiBasicTableColumn, + EuiPanel, + EuiTitle, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ValuesType } from 'utility-types'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; +import { + asDynamicBytes, + asInteger, +} from '../../../../../common/utils/formatters'; +import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; +import type { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { SizeLabel } from './size_label'; + +type StorageExplorerIndicesStats = + APIReturnType<'GET /internal/apm/services/{serviceName}/storage_details'>['indicesStats']; + +interface Props { + indicesStats: StorageExplorerIndicesStats; + status: FETCH_STATUS; +} + +export function IndexStatsPerService({ indicesStats, status }: Props) { + const columns: Array< + EuiBasicTableColumn> + > = [ + { + field: 'indexName', + name: i18n.translate('xpack.apm.storageExplorer.indicesStats.indexName', { + defaultMessage: 'Name', + }), + sortable: true, + }, + { + field: 'primary', + name: i18n.translate('xpack.apm.storageExplorer.indicesStats.primaries', { + defaultMessage: 'Primaries', + }), + render: (_, { primary }) => primary ?? NOT_AVAILABLE_LABEL, + sortable: true, + }, + { + field: 'replica', + name: i18n.translate('xpack.apm.storageExplorer.indicesStats.replicas', { + defaultMessage: 'Replicas', + }), + render: (_, { replica }) => replica ?? NOT_AVAILABLE_LABEL, + sortable: true, + }, + { + field: 'numberOfDocs', + name: i18n.translate( + 'xpack.apm.storageExplorer.indicesStats.numberOfDocs', + { + defaultMessage: 'Docs count', + } + ), + render: (_, { numberOfDocs }) => asInteger(numberOfDocs), + sortable: true, + }, + { + field: 'size', + name: , + render: (_, { size }) => asDynamicBytes(size) ?? NOT_AVAILABLE_LABEL, + sortable: true, + }, + { + field: 'dataStream', + name: i18n.translate( + 'xpack.apm.storageExplorer.indicesStats.dataStream', + { + defaultMessage: 'Data stream', + } + ), + render: (_, { dataStream }) => dataStream ?? NOT_AVAILABLE_LABEL, + sortable: true, + }, + { + field: 'lifecyclePhase', + name: i18n.translate( + 'xpack.apm.storageExplorer.indicesStats.lifecyclePhase', + { + defaultMessage: 'Lifecycle phase', + } + ), + render: (_, { lifecyclePhase }) => lifecyclePhase ?? NOT_AVAILABLE_LABEL, + sortable: true, + }, + ]; + + const loading = + status === FETCH_STATUS.NOT_INITIATED || status === FETCH_STATUS.LOADING; + + return ( + <> + +
+ {i18n.translate('xpack.apm.storageExplorer.indicesStats.title', { + defaultMessage: 'Indices breakdown', + })} +
+
+ + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/storage_details_per_service.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/storage_details_per_service.tsx index 0a101d3357684..4005c01f1b8f5 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/storage_details_per_service.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/storage_details_per_service.tsx @@ -41,6 +41,7 @@ import { asDynamicBytes } from '../../../../../common/utils/formatters'; import { getComparisonEnabled } from '../../../shared/time_comparison/get_comparison_enabled'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { SizeLabel } from './size_label'; +import { IndexStatsPerService } from './index_stats_per_service'; interface Props { serviceName: string; @@ -155,7 +156,7 @@ export function StorageDetailsPerService({ return ( <> - + @@ -265,6 +266,12 @@ export function StorageDetailsPerService({ + + + ); diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/storage_chart.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/storage_chart.tsx index 4aeb59fe58f9c..5ca58ebc7559e 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/storage_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/storage_chart.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { euiPaletteColorBlind, EuiPanel } from '@elastic/eui'; +import { euiPaletteColorBlind } from '@elastic/eui'; import { AreaSeries, Axis, @@ -83,56 +83,54 @@ export function StorageChart() { const isEmpty = isTimeseriesEmpty(storageTimeSeries); return ( - - - - + + + + + {storageTimeSeries.map((serie) => ( + - - - {storageTimeSeries.map((serie) => ( - - ))} - - - + ))} + + ); } 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 c5ffb336ca549..bb94e5c4507ca 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 @@ -14,30 +14,28 @@ import { EuiText, useEuiFontSize, EuiLink, - EuiLoadingSpinner, + EuiToolTip, + EuiIcon, + EuiProgress, + EuiLoadingContent, + EuiSpacer, } from '@elastic/eui'; import { useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; +import { isEmpty } from 'lodash'; import { useProgressiveFetcher } from '../../../hooks/use_progressive_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { asDynamicBytes } from '../../../../common/utils/formatters'; +import { asDynamicBytes, asPercent } from '../../../../common/utils/formatters'; import { useApmRouter } from '../../../hooks/use_apm_router'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { asTransactionRate } from '../../../../common/utils/formatters'; - -const INITIAL_DATA = { - estimatedSize: 0, - dailyDataGeneration: 0, - tracesPerMinute: 0, - numberOfServices: 0, -}; +import { getIndexManagementHref } from './get_storage_explorer_links'; export function SummaryStats() { const router = useApmRouter(); const { core } = useApmPluginContext(); - const { euiTheme } = useEuiTheme(); const { query: { @@ -63,7 +61,7 @@ export function SummaryStats() { }, }); - const { data = INITIAL_DATA, status } = useProgressiveFetcher( + const { data, status } = useProgressiveFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/storage_explorer_summary_stats', { params: { @@ -80,92 +78,136 @@ export function SummaryStats() { [indexLifecyclePhase, environment, kuery, start, end] ); - const loading = status === FETCH_STATUS.LOADING; + const loading = + status === FETCH_STATUS.LOADING || status === FETCH_STATUS.NOT_INITIATED; + + const hasData = !isEmpty(data); return ( - - {loading && ( - - - - )} - {!loading && ( - - - - - - + {loading && } + + + + + + + + + + + + + + + + + {i18n.translate( + 'xpack.apm.storageExplorer.summary.serviceInventoryLink', { - defaultMessage: 'Traces per minute', + defaultMessage: 'Go to Service Inventory', } )} - value={asTransactionRate(data?.tracesPerMinute)} - color={euiTheme.colors.accent} - /> - + + + + {i18n.translate( + 'xpack.apm.storageExplorer.summary.indexManagementLink', { - defaultMessage: 'Number of services', + defaultMessage: 'Go to Index Management', } )} - value={data?.numberOfServices.toString()} - color={euiTheme.colors.success} - /> - - - - - - - - {i18n.translate( - 'xpack.apm.storageExplorer.summary.serviceInventoryLink', - { - defaultMessage: 'Go to Service Inventory', - } - )} - - - - - {i18n.translate( - 'xpack.apm.storageExplorer.summary.indexManagementLink', - { - defaultMessage: 'Go to Index Management', - } - )} - - - - - - )} + + + + + ); } @@ -173,29 +215,55 @@ export function SummaryStats() { function SummaryMetric({ label, value, - color, + tooltipContent, + loading, + hasData, }: { label: string; value: string; - color: string; + tooltipContent?: string; + loading: boolean; + hasData: boolean; }) { - const xxlFontSize = useEuiFontSize('xxl', { measurement: 'px' }); + const xlFontSize = useEuiFontSize('xl', { measurement: 'px' }); const { euiTheme } = useEuiTheme(); return ( - - {label} - - - {value} - + {tooltipContent ? ( + + + {label}{' '} + + + + ) : ( + + {label} + + )} + {loading && !hasData && ( + <> + + + + )} + {hasData && ( + + {value} + + )} ); } diff --git a/x-pack/plugins/apm/public/components/routing/home/storage_explorer.tsx b/x-pack/plugins/apm/public/components/routing/home/storage_explorer.tsx index c4bc86f766811..167d4f88ca8b5 100644 --- a/x-pack/plugins/apm/public/components/routing/home/storage_explorer.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/storage_explorer.tsx @@ -6,18 +6,18 @@ */ import React from 'react'; -import { EuiTitle, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import * as t from 'io-ts'; import { EuiLink } from '@elastic/eui'; import { StorageExplorer } from '../../app/storage_explorer'; -import { BetaBadge } from '../../shared/beta_badge'; import { ApmMainTemplate } from '../templates/apm_main_template'; import { Breadcrumb } from '../../app/breadcrumb'; import { indexLifecyclePhaseRt, IndexLifecyclePhaseSelectOption, } from '../../../../common/storage_explorer_types'; +import { getStorageExplorerFeedbackHref } from '../../app/storage_explorer/get_storage_explorer_links'; export const storageExplorer = { '/storage-explorer': { @@ -32,30 +32,16 @@ export const storageExplorer = { pageHeader={{ alignItems: 'center', pageTitle: ( - - - -

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

-
-
- - - -
+ +

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

+
), rightSideItems: [ - + {i18n.translate( 'xpack.apm.views.storageExplorer.giveFeedback', { diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index ad3def1903517..58ff1bbfdb6ca 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -50,7 +50,7 @@ export function SparkPlot({ valueLabel: React.ReactNode; compact?: boolean; comparisonSeries?: Coordinate[]; - comparisonSeriesColor: string; + comparisonSeriesColor?: string; }) { return ( { }); it('enables auto-refresh when refreshPaused is false', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const { wrapper } = mountDatePicker({ rangeFrom: 'now-15m', rangeTo: 'now', @@ -139,7 +139,7 @@ describe('DatePicker', () => { }); it('disables auto-refresh when refreshPaused is true', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); mountDatePicker({ rangeFrom: 'now-15m', rangeTo: 'now', diff --git a/x-pack/plugins/apm/public/hooks/use_fetcher.integration.test.tsx b/x-pack/plugins/apm/public/hooks/use_fetcher.integration.test.tsx index 4b19ea5dddbda..27f29b7dff12e 100644 --- a/x-pack/plugins/apm/public/hooks/use_fetcher.integration.test.tsx +++ b/x-pack/plugins/apm/public/hooks/use_fetcher.integration.test.tsx @@ -23,7 +23,7 @@ describe('when simulating race condition', () => { let renderSpy: jest.Mock; beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); renderSpy = jest.fn(); requestCallOrder = []; diff --git a/x-pack/plugins/apm/public/hooks/use_fetcher.test.tsx b/x-pack/plugins/apm/public/hooks/use_fetcher.test.tsx index ed4d1f0791992..a25fcb7245451 100644 --- a/x-pack/plugins/apm/public/hooks/use_fetcher.test.tsx +++ b/x-pack/plugins/apm/public/hooks/use_fetcher.test.tsx @@ -36,7 +36,7 @@ describe('useFetcher', () => { >; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); async function fn() { await delay(500); return 'response from hook'; @@ -86,7 +86,7 @@ describe('useFetcher', () => { >; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); async function fn(): Promise { await delay(500); throw new Error('Something went wrong'); @@ -129,7 +129,7 @@ describe('useFetcher', () => { describe('when a hook already has data', () => { it('should show "first response" while loading "second response"', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const hook = renderHook( /* eslint-disable-next-line react-hooks/exhaustive-deps */ diff --git a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts index 8c55178d7bbed..624c3c626fe97 100644 --- a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts @@ -32,7 +32,7 @@ export function useServiceMetricChartsFetcher({ } = useApmParams('/services/{serviceName}'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const { agentName, serviceName, runtimeName } = useApmServiceContext(); + const { agentName, serviceName } = useApmServiceContext(); const { data = INITIAL_DATA, @@ -53,23 +53,13 @@ export function useServiceMetricChartsFetcher({ start, end, agentName, - serviceRuntimeName: runtimeName, }, }, } ); } }, - [ - environment, - kuery, - serviceName, - start, - end, - agentName, - serviceNodeName, - runtimeName, - ] + [environment, kuery, serviceName, start, end, agentName, serviceNodeName] ); return { diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/agent_config_instructions.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/agent_config_instructions.tsx index c7244002e59f5..0e4ad1f3f44a0 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/agent_config_instructions.tsx +++ b/x-pack/plugins/apm/public/tutorial/config_agent/agent_config_instructions.tsx @@ -25,7 +25,7 @@ export function AgentConfigInstructions({ }) { const defaultValues = { apmServiceName: 'my-service-name', - apmEnvironment: 'production', + apmEnvironment: 'my-environment', }; if (variantId === 'openTelemetry') { @@ -60,7 +60,11 @@ export function AgentConfigInstructions({ /> - + {commands} diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/commands/django.ts b/x-pack/plugins/apm/public/tutorial/config_agent/commands/django.ts index 4379f15c59cde..15279a71a6573 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/commands/django.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/commands/django.ts @@ -9,8 +9,8 @@ import { i18n } from '@kbn/i18n'; export const djangoVariables = { apmServiceName: 'SERVICE_NAME', - apmServerUrl: 'SERVER_URL', secretToken: 'SECRET_TOKEN', + apmServerUrl: 'SERVER_URL', apmEnvironment: 'ENVIRONMENT', }; @@ -21,50 +21,50 @@ export const django = `# ${i18n.translate( } )} INSTALLED_APPS = ( -'elasticapm.contrib.django', -# ... + 'elasticapm.contrib.django', + # ... ) ELASTIC_APM = { -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } -)} -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - } -)} -#'${djangoVariables.apmServiceName}': '{{{apmServiceName}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + } + )} + #'${djangoVariables.apmServiceName}': '{{{apmServiceName}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } -)} -'${djangoVariables.secretToken}': '{{{secretToken}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + '${djangoVariables.secretToken}': '{{{secretToken}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } -)} -'${djangoVariables.apmServerUrl}': '{{{apmServerUrl}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + '${djangoVariables.apmServerUrl}': '{{{apmServerUrl}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } -)} -'${djangoVariables.apmEnvironment}': '{{{apmEnvironment}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + '${djangoVariables.apmEnvironment}': '{{{apmEnvironment}}}', } # ${i18n.translate( @@ -74,6 +74,6 @@ ELASTIC_APM = { } )} MIDDLEWARE = ( -'elasticapm.contrib.django.middleware.TracingMiddleware', -#... + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... )`; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/commands/flask.ts b/x-pack/plugins/apm/public/tutorial/config_agent/commands/flask.ts index 11423c4e059db..a6289c0a88c1b 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/commands/flask.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/commands/flask.ts @@ -33,45 +33,45 @@ apm = ElasticAPM(app) )} from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } -)} -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - } -)} -#'${flaskVariables.apmServiceName}': '{{{apmServiceName}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + } + )} + #'${flaskVariables.apmServiceName}': '{{{apmServiceName}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } -)} -'${flaskVariables.secretToken}': '{{{secretToken}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + '${flaskVariables.secretToken}': '{{{secretToken}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } -)} -'${flaskVariables.apmServerUrl}': '{{{apmServerUrl}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + '${flaskVariables.apmServerUrl}': '{{{apmServerUrl}}}', -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } -)} -'${flaskVariables.apmEnvironment}': '{{{apmEnvironment}}}', + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + '${flaskVariables.apmEnvironment}': '{{{apmEnvironment}}}', } apm = ElasticAPM(app)`; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/commands/get_apm_agent_commands.test.ts b/x-pack/plugins/apm/public/tutorial/config_agent/commands/get_apm_agent_commands.test.ts index efbcfae955a55..d01d3acc5d519 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/commands/get_apm_agent_commands.test.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/commands/get_apm_agent_commands.test.ts @@ -10,7 +10,7 @@ import { getApmAgentCommands } from './get_apm_agent_commands'; describe('getCommands', () => { const defaultValues = { apmServiceName: 'my-service-name', - apmEnvironment: 'production', + apmEnvironment: 'my-environment', }; describe('unknown agent', () => { it('renders empty command', () => { @@ -37,7 +37,7 @@ describe('getCommands', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url= \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -57,7 +57,7 @@ describe('getCommands', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token=foobar \\\\ -Delastic.apm.server_url=localhost:8220 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -85,7 +85,7 @@ describe('getCommands', () => { serviceVersion: '', // Set the service environment - environment: 'production' + environment: 'my-environment' })" `); }); @@ -113,7 +113,7 @@ describe('getCommands', () => { serviceVersion: '', // Set the service environment - environment: 'production' + environment: 'my-environment' })" `); }); @@ -130,18 +130,18 @@ describe('getCommands', () => { "// Add this to the VERY top of the first file loaded in your app var apm = require('elastic-apm-node').start({ - // Override the service name from package.json - // Allowed characters: a-z, A-Z, 0-9, -, _, and space - serviceName: 'my-service-name', + // Override the service name from package.json + // Allowed characters: a-z, A-Z, 0-9, -, _, and space + serviceName: 'my-service-name', - // Use if APM Server requires a secret token - secretToken: '', + // Use if APM Server requires a secret token + secretToken: '', - // Set the custom APM Server URL (default: http://localhost:8200) - serverUrl: '', + // Set the custom APM Server URL (default: http://localhost:8200) + serverUrl: '', - // Set the service environment - environment: 'production' + // Set the service environment + environment: 'my-environment' })" `); }); @@ -159,18 +159,18 @@ describe('getCommands', () => { "// Add this to the VERY top of the first file loaded in your app var apm = require('elastic-apm-node').start({ - // Override the service name from package.json - // Allowed characters: a-z, A-Z, 0-9, -, _, and space - serviceName: 'my-service-name', + // Override the service name from package.json + // Allowed characters: a-z, A-Z, 0-9, -, _, and space + serviceName: 'my-service-name', - // Use if APM Server requires a secret token - secretToken: 'foobar', + // Use if APM Server requires a secret token + secretToken: 'foobar', - // Set the custom APM Server URL (default: http://localhost:8200) - serverUrl: 'localhost:8220', + // Set the custom APM Server URL (default: http://localhost:8200) + serverUrl: 'localhost:8220', - // Set the service environment - environment: 'production' + // Set the service environment + environment: 'my-environment' })" `); }); @@ -186,29 +186,29 @@ describe('getCommands', () => { expect(commands).toMatchInlineSnapshot(` "# Add the agent to the installed apps INSTALLED_APPS = ( - 'elasticapm.contrib.django', - # ... + 'elasticapm.contrib.django', + # ... ) ELASTIC_APM = { - # Set the required service name. Allowed characters: - # a-z, A-Z, 0-9, -, _, and space - #'SERVICE_NAME': 'my-service-name', + # Set the required service name. Allowed characters: + # a-z, A-Z, 0-9, -, _, and space + #'SERVICE_NAME': 'my-service-name', - # Use if APM Server requires a secret token - 'SECRET_TOKEN': '', + # Use if APM Server requires a secret token + 'SECRET_TOKEN': '', - # Set the custom APM Server URL (default: http://localhost:8200) - 'SERVER_URL': '', + # Set the custom APM Server URL (default: http://localhost:8200) + 'SERVER_URL': '', - # Set the service environment - 'ENVIRONMENT': 'production', + # Set the service environment + 'ENVIRONMENT': 'my-environment', } # To send performance metrics, add our tracing middleware: MIDDLEWARE = ( - 'elasticapm.contrib.django.middleware.TracingMiddleware', - #... + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... )" `); }); @@ -225,29 +225,29 @@ describe('getCommands', () => { expect(commands).toMatchInlineSnapshot(` "# Add the agent to the installed apps INSTALLED_APPS = ( - 'elasticapm.contrib.django', - # ... + 'elasticapm.contrib.django', + # ... ) ELASTIC_APM = { - # Set the required service name. Allowed characters: - # a-z, A-Z, 0-9, -, _, and space - #'SERVICE_NAME': 'my-service-name', + # Set the required service name. Allowed characters: + # a-z, A-Z, 0-9, -, _, and space + #'SERVICE_NAME': 'my-service-name', - # Use if APM Server requires a secret token - 'SECRET_TOKEN': 'foobar', + # Use if APM Server requires a secret token + 'SECRET_TOKEN': 'foobar', - # Set the custom APM Server URL (default: http://localhost:8200) - 'SERVER_URL': 'localhost:8220', + # Set the custom APM Server URL (default: http://localhost:8200) + 'SERVER_URL': 'localhost:8220', - # Set the service environment - 'ENVIRONMENT': 'production', + # Set the service environment + 'ENVIRONMENT': 'my-environment', } # To send performance metrics, add our tracing middleware: MIDDLEWARE = ( - 'elasticapm.contrib.django.middleware.TracingMiddleware', - #... + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... )" `); }); @@ -269,18 +269,18 @@ describe('getCommands', () => { # or configure to use ELASTIC_APM in your application's settings from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { - # Set the required service name. Allowed characters: - # a-z, A-Z, 0-9, -, _, and space - #'SERVICE_NAME': 'my-service-name', + # Set the required service name. Allowed characters: + # a-z, A-Z, 0-9, -, _, and space + #'SERVICE_NAME': 'my-service-name', - # Use if APM Server requires a secret token - 'SECRET_TOKEN': '', + # Use if APM Server requires a secret token + 'SECRET_TOKEN': '', - # Set the custom APM Server URL (default: http://localhost:8200) - 'SERVER_URL': '', + # Set the custom APM Server URL (default: http://localhost:8200) + 'SERVER_URL': '', - # Set the service environment - 'ENVIRONMENT': 'production', + # Set the service environment + 'ENVIRONMENT': 'my-environment', } apm = ElasticAPM(app)" @@ -305,18 +305,18 @@ describe('getCommands', () => { # or configure to use ELASTIC_APM in your application's settings from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { - # Set the required service name. Allowed characters: - # a-z, A-Z, 0-9, -, _, and space - #'SERVICE_NAME': 'my-service-name', + # Set the required service name. Allowed characters: + # a-z, A-Z, 0-9, -, _, and space + #'SERVICE_NAME': 'my-service-name', - # Use if APM Server requires a secret token - 'SECRET_TOKEN': 'foobar', + # Use if APM Server requires a secret token + 'SECRET_TOKEN': 'foobar', - # Set the custom APM Server URL (default: http://localhost:8200) - 'SERVER_URL': 'localhost:8220', + # Set the custom APM Server URL (default: http://localhost:8200) + 'SERVER_URL': 'localhost:8220', - # Set the service environment - 'ENVIRONMENT': 'production', + # Set the service environment + 'ENVIRONMENT': 'my-environment', } apm = ElasticAPM(app)" @@ -345,7 +345,7 @@ describe('getCommands', () => { server_url: '' # Set the service environment - environment: 'production'" + environment: 'my-environment'" `); }); it('renders with secret token and url', () => { @@ -372,7 +372,7 @@ describe('getCommands', () => { server_url: 'localhost:8220' # Set the service environment - environment: 'production'" + environment: 'my-environment'" `); }); }); @@ -398,7 +398,7 @@ describe('getCommands', () => { server_url: '', # Set the service environment - environment: 'production'" + environment: 'my-environment'" `); }); it('renders with secret token and url', () => { @@ -425,7 +425,7 @@ describe('getCommands', () => { server_url: 'localhost:8220', # Set the service environment - environment: 'production'" + environment: 'my-environment'" `); }); }); @@ -451,7 +451,7 @@ describe('getCommands', () => { export ELASTIC_APM_SERVER_URL= # Set the service environment - export ELASTIC_APM_ENVIRONMENT=production + export ELASTIC_APM_ENVIRONMENT=my-environment " `); }); @@ -479,7 +479,7 @@ describe('getCommands', () => { export ELASTIC_APM_SERVER_URL=localhost:8220 # Set the service environment - export ELASTIC_APM_ENVIRONMENT=production + export ELASTIC_APM_ENVIRONMENT=my-environment " `); }); @@ -498,7 +498,7 @@ describe('getCommands', () => { \\"ServiceName\\": \\"my-service-name\\", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application \\"SecretToken\\": \\"\\", \\"ServerUrl\\": \\"\\", //Set custom APM Server URL (default: http://localhost:8200) - \\"Environment\\": \\"production\\", // Set the service environment + \\"Environment\\": \\"my-environment\\", // Set the service environment } }" `); @@ -519,7 +519,7 @@ describe('getCommands', () => { \\"ServiceName\\": \\"my-service-name\\", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application \\"SecretToken\\": \\"foobar\\", \\"ServerUrl\\": \\"localhost:8220\\", //Set custom APM Server URL (default: http://localhost:8200) - \\"Environment\\": \\"production\\", // Set the service environment + \\"Environment\\": \\"my-environment\\", // Set the service environment } }" `); @@ -537,7 +537,7 @@ describe('getCommands', () => { "elastic_apm.service_name=\\"my-service-name\\" elastic_apm.secret_token=\\"\\" elastic_apm.server_url=\\"\\" - elastic_apm.environment=\\"production\\" + elastic_apm.environment=\\"my-environment\\" " `); }); @@ -555,7 +555,7 @@ describe('getCommands', () => { "elastic_apm.service_name=\\"my-service-name\\" elastic_apm.secret_token=\\"foobar\\" elastic_apm.server_url=\\"localhost:8220\\" - elastic_apm.environment=\\"production\\" + elastic_apm.environment=\\"my-environment\\" " `); }); diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/commands/java.ts b/x-pack/plugins/apm/public/tutorial/config_agent/commands/java.ts index 2d056b3a242f3..4edcb6aab2170 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/commands/java.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/commands/java.ts @@ -16,6 +16,6 @@ export const java = `java -javaagent:/path/to/elastic-apm-agent-.jar \\ -${javaVariables.apmServiceName}={{{apmServiceName}}} \\ -${javaVariables.secretToken}={{{secretToken}}} \\ -${javaVariables.apmServerUrl}={{{apmServerUrl}}} \\ --${javaVariables.apmEnvironment}=production \\ +-${javaVariables.apmEnvironment}={{{apmEnvironment}}} \\ -Delastic.apm.application_packages=org.example \\ -jar {{{apmServiceName}}}.jar`; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/commands/node.ts b/x-pack/plugins/apm/public/tutorial/config_agent/commands/node.ts index 8b8ba07a7cb9c..2510599cff94e 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/commands/node.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/commands/node.ts @@ -22,43 +22,43 @@ export const node = `// ${i18n.translate( )} var apm = require('elastic-apm-node').start({ -// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Override the service name from package.json', - } -)} -// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', - } -)} -${nodeVariables.apmServiceName}: '{{{apmServiceName}}}', + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Override the service name from package.json', + } + )} + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', + } + )} + ${nodeVariables.apmServiceName}: '{{{apmServiceName}}}', -// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } -)} -${nodeVariables.secretToken}: '{{{secretToken}}}', + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + ${nodeVariables.secretToken}: '{{{secretToken}}}', -// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } -)} -${nodeVariables.apmServerUrl}: '{{{apmServerUrl}}}', + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + ${nodeVariables.apmServerUrl}: '{{{apmServerUrl}}}', -// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } -)} -${nodeVariables.apmEnvironment}: '{{{apmEnvironment}}}' + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + ${nodeVariables.apmEnvironment}: '{{{apmEnvironment}}}' })`; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx index b1ebe783518d0..edae01e0b6043 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx +++ b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx @@ -90,7 +90,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url=http://localhost:8200 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -104,7 +104,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token=foo token \\\\ -Delastic.apm.server_url=foo url \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -141,7 +141,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url=http://localhost:8200 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -177,7 +177,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url=http://localhost:8200 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -219,7 +219,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token=cloud_token \\\\ -Delastic.apm.server_url=cloud_url \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -258,7 +258,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token=apm_cloud_token \\\\ -Delastic.apm.server_url=apm_cloud_url \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -290,7 +290,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url=http://localhost:8200 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -353,7 +353,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token= \\\\ -Delastic.apm.server_url=http://localhost:8200 \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -390,7 +390,7 @@ describe('TutorialConfigAgent', () => { -Delastic.apm.service_name=my-service-name \\\\ -Delastic.apm.secret_token=cloud_token \\\\ -Delastic.apm.server_url=cloud_url \\\\ - -Delastic.apm.environment=production \\\\ + -Delastic.apm.environment=my-environment \\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts index a9c7745178219..4c76699d2089b 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_destination_map.ts @@ -24,10 +24,10 @@ import { SPAN_SUBTYPE, SPAN_TYPE, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../helpers/setup_request'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Node, NodeType } from '../../../../common/connections'; import { excludeRumExitSpansQuery } from '../exclude_rum_exit_spans_query'; +import { APMEventClient } from '../../helpers/create_es_client/create_apm_event_client'; type Destination = { dependencyName: string; @@ -48,21 +48,19 @@ type Destination = { // - for each span, find the transaction it creates // - if there is a transaction, match the dependency name (span.destination.service.resource) to a service export const getDestinationMap = ({ - setup, + apmEventClient, start, end, filter, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; filter: QueryDslQueryContainer[]; offset?: string; }) => { return withApmSpan('get_destination_map', async () => { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts index 7057847c34c0c..409565db5729f 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts @@ -27,27 +27,25 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { EventOutcome } from '../../../../common/event_outcome'; -import { Setup } from '../../helpers/setup_request'; import { NodeType } from '../../../../common/connections'; import { excludeRumExitSpansQuery } from '../exclude_rum_exit_spans_query'; +import { APMEventClient } from '../../helpers/create_es_client/create_apm_event_client'; export const getStats = async ({ - setup, + apmEventClient, start, end, filter, numBuckets, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; filter: QueryDslQueryContainer[]; numBuckets: number; offset?: string; }) => { - const { apmEventClient } = setup; - const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts index 7c9781e08db31..4ba113b698bc1 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/index.ts @@ -9,14 +9,14 @@ import { ValuesType } from 'utility-types'; import { merge } from 'lodash'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { joinByKey } from '../../../../common/utils/join_by_key'; -import { Setup } from '../../helpers/setup_request'; import { getStats } from './get_stats'; import { getDestinationMap } from './get_destination_map'; import { calculateThroughputWithRange } from '../../helpers/calculate_throughput'; import { withApmSpan } from '../../../utils/with_apm_span'; +import { APMEventClient } from '../../helpers/create_es_client/create_apm_event_client'; export function getConnectionStats({ - setup, + apmEventClient, start, end, numBuckets, @@ -24,7 +24,7 @@ export function getConnectionStats({ collapseBy, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; numBuckets: number; @@ -35,7 +35,7 @@ export function getConnectionStats({ return withApmSpan('get_connection_stats_and_map', async () => { const [allMetrics, destinationMap] = await Promise.all([ getStats({ - setup, + apmEventClient, start, end, filter, @@ -43,7 +43,7 @@ export function getConnectionStats({ offset, }), getDestinationMap({ - setup, + apmEventClient, start, end, filter, diff --git a/x-pack/plugins/apm/server/lib/helpers/get_apm_event_client.ts b/x-pack/plugins/apm/server/lib/helpers/get_apm_event_client.ts new file mode 100644 index 0000000000000..6ee9bb94a62b2 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/helpers/get_apm_event_client.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UI_SETTINGS } from '@kbn/data-plugin/common'; +import { APMRouteHandlerResources } from '../../routes/typings'; +import { getApmIndices } from '../../routes/settings/apm_indices/get_apm_indices'; +import { APMEventClient } from './create_es_client/create_apm_event_client'; +import { withApmSpan } from '../../utils/with_apm_span'; + +export async function getApmEventClient({ + context, + params, + config, + request, +}: APMRouteHandlerResources): Promise { + return withApmSpan('get_apm_event_client', async () => { + const coreContext = await context.core; + const [indices, includeFrozen] = await Promise.all([ + getApmIndices({ + savedObjectsClient: coreContext.savedObjects.client, + config, + }), + withApmSpan('get_ui_settings', () => + coreContext.uiSettings.client.get( + UI_SETTINGS.SEARCH_INCLUDE_FROZEN + ) + ), + ]); + + return new APMEventClient({ + esClient: coreContext.elasticsearch.client.asCurrentUser, + debug: params.query._inspect, + request, + indices, + options: { includeFrozen }, + }); + }); +} diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts index faaeb5db91405..ef8dcbbe63ee2 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts @@ -9,7 +9,6 @@ import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { setupRequest } from './setup_request'; import { APMConfig } from '../..'; import { APMRouteHandlerResources } from '../../routes/typings'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getApmIndices } from '../../routes/settings/apm_indices/get_apm_indices'; jest.mock('../../routes/settings/apm_indices/get_apm_indices', () => ({ @@ -97,38 +96,6 @@ function getMockResources() { describe('setupRequest', () => { describe('with default args', () => { - it('calls callWithRequest', async () => { - const mockResources = getMockResources(); - const { apmEventClient } = await setupRequest(mockResources); - await apmEventClient.search('foo', { - apm: { events: [ProcessorEvent.transaction] }, - body: { track_total_hits: 10_000, size: 10 }, - }); - - expect( - mockResources.context.core.elasticsearch.client.asCurrentUser.search - ).toHaveBeenCalledWith( - { - index: ['apm-*'], - body: { - track_total_hits: 10000, - size: 10, - query: { - bool: { - filter: [{ terms: { 'processor.event': ['transaction'] } }], - }, - }, - }, - ignore_unavailable: true, - preference: 'any', - }, - { - signal: expect.any(Object), - meta: true, - } - ); - }); - it('calls callWithInternalUser', async () => { const mockResources = getMockResources(); const { internalClient } = await setupRequest(mockResources); @@ -153,49 +120,3 @@ describe('setupRequest', () => { }); }); }); - -describe('with includeFrozen=false', () => { - it('should NOT send "ignore_throttled:true" in the request', async () => { - const mockResources = getMockResources(); - - // mock includeFrozen to return false - mockResources.context.core.uiSettings.client.get.mockResolvedValue(false); - - const { apmEventClient } = await setupRequest(mockResources); - - await apmEventClient.search('foo', { - apm: { - events: [], - }, - body: { track_total_hits: 10_000, size: 10 }, - }); - - const params = - mockResources.context.core.elasticsearch.client.asCurrentUser.search.mock - .calls[0][0]; - // @ts-expect-error missing body definition - expect(params.ignore_throttled).toBe(undefined); - }); -}); - -describe('with includeFrozen=true', () => { - it('sets `ignore_throttled=false`', async () => { - const mockResources = getMockResources(); - - // mock includeFrozen to return true - mockResources.context.core.uiSettings.client.get.mockResolvedValue(true); - - const { apmEventClient } = await setupRequest(mockResources); - - await apmEventClient.search('foo', { - apm: { events: [] }, - body: { track_total_hits: 10_000, size: 10 }, - }); - - const params = - mockResources.context.core.elasticsearch.client.asCurrentUser.search.mock - .calls[0][0]; - // @ts-expect-error missing body definition - expect(params.ignore_throttled).toBe(false); - }); -}); diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts index dc6e379367408..457c002c67b97 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts @@ -14,7 +14,6 @@ import { ApmIndicesConfig, getApmIndices, } from '../../routes/settings/apm_indices/get_apm_indices'; -import { APMEventClient } from './create_es_client/create_apm_event_client'; import { APMInternalClient, createInternalESClient, @@ -25,7 +24,6 @@ import { withApmSpan } from '../../utils/with_apm_span'; // https://github.com/microsoft/TypeScript/issues/34933 export interface Setup { - apmEventClient: APMEventClient; internalClient: APMInternalClient; ml?: ReturnType; config: APMConfig; @@ -45,7 +43,7 @@ export async function setupRequest({ const coreContext = await context.core; const licensingContext = await context.licensing; - const [indices, includeFrozen] = await Promise.all([ + const [indices] = await Promise.all([ getApmIndices({ savedObjectsClient: coreContext.savedObjects.client, config, @@ -59,13 +57,6 @@ export async function setupRequest({ return { indices, - apmEventClient: new APMEventClient({ - esClient: coreContext.elasticsearch.client.asCurrentUser, - debug: query._inspect, - request, - indices, - options: { includeFrozen }, - }), internalClient: await createInternalESClient({ context, request, diff --git a/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts b/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts index 0dbf3006a324d..6b58db02bbbbc 100644 --- a/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts +++ b/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts @@ -19,7 +19,7 @@ import { SPAN_DURATION, SPAN_NAME, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../setup_request'; +import { APMEventClient } from '../create_es_client/create_apm_event_client'; export function getProcessorEventForServiceDestinationStatistics( searchServiceDestinationMetrics: boolean @@ -54,20 +54,18 @@ export function getDocCountFieldForServiceDestinationStatistics( } export async function getIsUsingServiceDestinationMetrics({ - setup, + apmEventClient, useSpanName, kuery, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; useSpanName: boolean; kuery: string; start: number; end: number; }) { - const { apmEventClient } = setup; - async function getServiceDestinationMetricsCount( query?: QueryDslQueryContainer ) { diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts index 1fac873ced7be..97b4fcbf9584c 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.test.ts @@ -63,7 +63,12 @@ describe('getIsUsingTransactionEvents', () => { it('should be false', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config } ); expect(mock.response).toBe(false); @@ -71,7 +76,12 @@ describe('getIsUsingTransactionEvents', () => { it('should not query for data', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config } ); expect(mock.spy).toHaveBeenCalledTimes(0); @@ -84,7 +94,12 @@ describe('getIsUsingTransactionEvents', () => { }; it('should be false when kuery is empty', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config } ); expect(mock.response).toBe(false); @@ -92,9 +107,10 @@ describe('getIsUsingTransactionEvents', () => { it('should be false when kuery is set and metrics data found', async () => { mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getIsUsingTransactionEvents({ - setup, + config: setup.config, + apmEventClient, kuery: 'proccessor.event: "transaction"', }), { @@ -116,9 +132,10 @@ describe('getIsUsingTransactionEvents', () => { it('should be true when kuery is set and metrics data are not found', async () => { mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getIsUsingTransactionEvents({ - setup, + config: setup.config, + apmEventClient, kuery: 'proccessor.event: "transaction"', }), { @@ -140,7 +157,12 @@ describe('getIsUsingTransactionEvents', () => { it('should not query for data when kuery is empty', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config } ); expect(mock.spy).toHaveBeenCalledTimes(0); @@ -148,9 +170,10 @@ describe('getIsUsingTransactionEvents', () => { it('should query for data when kuery is set', async () => { mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getIsUsingTransactionEvents({ - setup, + config: setup.config, + apmEventClient, kuery: 'proccessor.event: "transaction"', }), { config } @@ -167,7 +190,12 @@ describe('getIsUsingTransactionEvents', () => { it('should query for data once if metrics data found', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config, mockResponse: (request) => { @@ -187,7 +215,12 @@ describe('getIsUsingTransactionEvents', () => { it('should query for data twice if metrics data not found', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config, mockResponse: (request) => { @@ -207,7 +240,12 @@ describe('getIsUsingTransactionEvents', () => { it('should be false if metrics data are found', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config, mockResponse: (request) => { @@ -226,7 +264,12 @@ describe('getIsUsingTransactionEvents', () => { it('should be true if no metrics data are found', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config, mockResponse: (request) => { @@ -245,7 +288,12 @@ describe('getIsUsingTransactionEvents', () => { it('should be false if no metrics or transactions data are found', async () => { mock = await inspectSearchParams( - (setup) => getIsUsingTransactionEvents({ setup, kuery: '' }), + (setup, apmEventClient) => + getIsUsingTransactionEvents({ + config: setup.config, + apmEventClient, + kuery: '', + }), { config, mockResponse: () => mockResponseNoHits } ); expect(mock.response).toBe(false); diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts index 409010d3c695d..20832c70d007b 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts @@ -8,17 +8,19 @@ import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getSearchTransactionsEvents } from '.'; -import { Setup } from '../setup_request'; import { APMEventClient } from '../create_es_client/create_apm_event_client'; import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions'; +import { APMConfig } from '../../..'; export async function getIsUsingTransactionEvents({ - setup: { config, apmEventClient }, + config, + apmEventClient, kuery, start, end, }: { - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; kuery: string; start?: number; end?: number; diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_coldstart_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_coldstart_rate.ts index c16b600cda146..74419d47507a4 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_coldstart_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_coldstart_rate.ts @@ -21,13 +21,13 @@ import { getProcessorEventForTransactions, } from '../helpers/transactions'; import { getBucketSizeForAggregatedTransactions } from '../helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../helpers/setup_request'; import { calculateTransactionColdstartRate, getColdstartAggregation, getTransactionColdstartRateTimeSeries, } from '../helpers/transaction_coldstart_rate'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../helpers/create_es_client/create_apm_event_client'; export async function getColdstartRate({ environment, @@ -35,7 +35,7 @@ export async function getColdstartRate({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -46,7 +46,7 @@ export async function getColdstartRate({ serviceName: string; transactionType?: string; transactionName: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; @@ -55,8 +55,6 @@ export async function getColdstartRate({ transactionColdstartRate: Coordinate[]; average: number | null; }> { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -131,7 +129,7 @@ export async function getColdstartRatePeriods({ serviceName, transactionType, transactionName = '', - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -142,7 +140,7 @@ export async function getColdstartRatePeriods({ serviceName: string; transactionType?: string; transactionName?: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; @@ -154,7 +152,7 @@ export async function getColdstartRatePeriods({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, }; diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts index 6cebbce9d974c..8fb57d037a3c6 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts @@ -24,13 +24,13 @@ import { getProcessorEventForTransactions, } from '../helpers/transactions'; import { getBucketSizeForAggregatedTransactions } from '../helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../helpers/setup_request'; import { calculateFailedTransactionRate, getOutcomeAggregation, getFailedTransactionRateTimeSeries, } from '../helpers/transaction_error_rate'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../helpers/create_es_client/create_apm_event_client'; export async function getFailedTransactionRate({ environment, @@ -38,7 +38,7 @@ export async function getFailedTransactionRate({ serviceName, transactionTypes, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -50,7 +50,7 @@ export async function getFailedTransactionRate({ serviceName: string; transactionTypes: string[]; transactionName?: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; @@ -60,8 +60,6 @@ export async function getFailedTransactionRate({ timeseries: Coordinate[]; average: number | null; }> { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/alerts/route.ts b/x-pack/plugins/apm/server/routes/alerts/route.ts index 56e23d2712868..389f6fc87c24b 100644 --- a/x-pack/plugins/apm/server/routes/alerts/route.ts +++ b/x-pack/plugins/apm/server/routes/alerts/route.ts @@ -13,6 +13,7 @@ import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, rangeRt } from '../default_api_types'; import { AggregationType } from '../../../common/rules/apm_rule_types'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const alertParamsRt = t.intersection([ t.partial({ @@ -40,12 +41,16 @@ const transactionErrorRateChartPreview = createApmServerRoute({ handler: async ( resources ): Promise<{ errorRateChartPreview: Array<{ x: number; y: number }> }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { _inspect, ...alertParams } = params.query; const errorRateChartPreview = await getTransactionErrorRateChartPreview({ - setup, + config: setup.config, + apmEventClient, alertParams, }); @@ -60,13 +65,13 @@ const transactionErrorCountChartPreview = createApmServerRoute({ handler: async ( resources ): Promise<{ errorCountChartPreview: Array<{ x: number; y: number }> }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { _inspect, ...alertParams } = params.query; const errorCountChartPreview = await getTransactionErrorCountChartPreview({ - setup, + apmEventClient, alertParams, }); @@ -86,7 +91,10 @@ const transactionDurationChartPreview = createApmServerRoute({ data: Array<{ x: number; y: number | null }>; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; @@ -94,7 +102,8 @@ const transactionDurationChartPreview = createApmServerRoute({ const latencyChartPreview = await getTransactionDurationChartPreview({ alertParams, - setup, + config: setup.config, + apmEventClient, }); return { latencyChartPreview }; diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts index 3489ae4d91be6..fa819e268c802 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts @@ -10,16 +10,15 @@ import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames'; import { AlertParams } from '../../route'; import { environmentQuery } from '../../../../../common/utils/environment_query'; -import { Setup } from '../../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransactionErrorCountChartPreview({ - setup, + apmEventClient, alertParams, }: { - setup: Setup; + apmEventClient: APMEventClient; alertParams: AlertParams; }) { - const { apmEventClient } = setup; const { serviceName, environment, interval, start, end } = alertParams; const query = { diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts index ad01f8a4c3c25..292748f3af16c 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts @@ -21,21 +21,23 @@ import { getDurationFieldForTransactions, getProcessorEventForTransactions, } from '../../../../lib/helpers/transactions'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED, getEnvironmentLabel, } from '../../../../../common/environment_filter_values'; import { averageOrPercentileAgg } from '../../average_or_percentile_agg'; +import { APMConfig } from '../../../..'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransactionDurationChartPreview({ alertParams, - setup, + config, + apmEventClient, }: { alertParams: AlertParams; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; }) { - const { apmEventClient } = setup; const { aggregationType = AggregationType.Avg, environment, @@ -46,7 +48,8 @@ export async function getTransactionDurationChartPreview({ end, } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config, + apmEventClient, kuery: '', }); diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts index 9921b0ce16a3f..d799e025c3453 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts @@ -17,25 +17,28 @@ import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../../../lib/helpers/transactions'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { calculateFailedTransactionRate, getOutcomeAggregation, } from '../../../../lib/helpers/transaction_error_rate'; +import { APMConfig } from '../../../..'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransactionErrorRateChartPreview({ - setup, + config, + apmEventClient, alertParams, }: { - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; alertParams: AlertParams; }) { - const { apmEventClient } = setup; const { serviceName, environment, transactionType, interval, start, end } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config, + apmEventClient, kuery: '', start, end, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation.ts index 74ef7bc56fdce..48d468c517972 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation.ts @@ -12,12 +12,11 @@ import { TRANSACTION_DURATION, } from '../../../../common/elasticsearch_fieldnames'; import type { CommonCorrelationsQueryParams } from '../../../../common/correlations/types'; - -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchDurationCorrelation = async ({ - setup, + apmEventClient, eventType, start, end, @@ -29,7 +28,7 @@ export const fetchDurationCorrelation = async ({ fractions, totalDocCount, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent; expectations: number[]; ranges: estypes.AggregationsAggregationRange[]; @@ -40,8 +39,6 @@ export const fetchDurationCorrelation = async ({ correlation: number | null; ksTest: number | null; }> => { - const { apmEventClient } = setup; - const resp = await apmEventClient.search('get_duration_correlation', { apm: { events: [eventType], diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation_with_histogram.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation_with_histogram.ts index 4fd82d431af67..a4b2b0c6284d5 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation_with_histogram.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_correlation_with_histogram.ts @@ -19,13 +19,13 @@ import { } from '../../../../common/correlations/constants'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; -import { Setup } from '../../../lib/helpers/setup_request'; import { fetchDurationCorrelation } from './fetch_duration_correlation'; import { fetchDurationRanges } from './fetch_duration_ranges'; import { getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function fetchDurationCorrelationWithHistogram({ - setup, + apmEventClient, chartType, start, end, @@ -39,7 +39,7 @@ export async function fetchDurationCorrelationWithHistogram({ totalDocCount, fieldValuePair, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; chartType: LatencyDistributionChartType; expectations: number[]; ranges: estypes.AggregationsAggregationRange[]; @@ -60,7 +60,7 @@ export async function fetchDurationCorrelationWithHistogram({ }; const { correlation, ksTest } = await fetchDurationCorrelation({ - setup, + apmEventClient, eventType, start, end, @@ -76,7 +76,7 @@ export async function fetchDurationCorrelationWithHistogram({ if (correlation !== null && ksTest !== null && !isNaN(ksTest)) { if (correlation > CORRELATION_THRESHOLD && ksTest < KS_TEST_THRESHOLD) { const { durationRanges: histogram } = await fetchDurationRanges({ - setup, + apmEventClient, chartType, start, end, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts index 29863b52c42bb..c15f40d78d2c1 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts @@ -16,9 +16,8 @@ import { POPULATED_DOC_COUNT_SAMPLE_SIZE, } from '../../../../common/correlations/constants'; import { hasPrefixToInclude } from '../../../../common/correlations/utils'; - -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; const SUPPORTED_ES_FIELD_TYPES = [ ES_FIELD_TYPES.KEYWORD, @@ -36,7 +35,7 @@ export const shouldBeExcluded = (fieldName: string) => { }; export const fetchDurationFieldCandidates = async ({ - setup, + apmEventClient, eventType, query, start, @@ -45,13 +44,11 @@ export const fetchDurationFieldCandidates = async ({ kuery, }: CommonCorrelationsQueryParams & { query: estypes.QueryDslQueryContainer; - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent.transaction | ProcessorEvent.span; }): Promise<{ fieldCandidates: string[]; }> => { - const { apmEventClient } = setup; - // Get all supported fields const [respMapping, respRandomDoc] = await Promise.all([ apmEventClient.fieldCaps('get_field_caps', { diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_fractions.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_fractions.ts index c77399d215d51..222cce131372d 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_fractions.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_fractions.ts @@ -13,14 +13,14 @@ import { SPAN_DURATION, TRANSACTION_DURATION, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; /** * Compute the actual percentile bucket counts and actual fractions */ export const fetchDurationFractions = async ({ - setup, + apmEventClient, eventType, start, end, @@ -29,11 +29,10 @@ export const fetchDurationFractions = async ({ query, ranges, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent; ranges: estypes.AggregationsAggregationRange[]; }): Promise<{ fractions: number[]; totalDocCount: number }> => { - const { apmEventClient } = setup; const resp = await apmEventClient.search('get_duration_fractions', { apm: { events: [eventType], diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts index 4e7c852ca9924..7e86fc70bad79 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts @@ -10,9 +10,9 @@ import { scaleLog } from 'd3-scale'; import { isFiniteNumber } from '@kbn/observability-plugin/common/utils/is_finite_number'; import { CommonCorrelationsQueryParams } from '../../../../common/correlations/types'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; import { getDurationField, getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; const getHistogramRangeSteps = (min: number, max: number, steps: number) => { // A d3 based scale function as a helper to get equally distributed bins on a log scale. @@ -25,7 +25,7 @@ const getHistogramRangeSteps = (min: number, max: number, steps: number) => { export const fetchDurationHistogramRangeSteps = async ({ chartType, - setup, + apmEventClient, start, end, environment, @@ -36,7 +36,7 @@ export const fetchDurationHistogramRangeSteps = async ({ durationMaxOverride, }: CommonCorrelationsQueryParams & { chartType: LatencyDistributionChartType; - setup: Setup; + apmEventClient: APMEventClient; searchMetrics: boolean; durationMinOverride?: number; durationMaxOverride?: number; @@ -59,8 +59,6 @@ export const fetchDurationHistogramRangeSteps = async ({ }; } - const { apmEventClient } = setup; - const durationField = getDurationField(chartType, searchMetrics); // when using metrics data, ensure we filter by docs with the appropriate duration field diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.ts index 618ee3a321939..d303777b08c79 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.ts @@ -6,15 +6,15 @@ */ import { SIGNIFICANT_VALUE_DIGITS } from '../../../../common/correlations/constants'; -import { Setup } from '../../../lib/helpers/setup_request'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; import { CommonCorrelationsQueryParams } from '../../../../common/correlations/types'; import { getDurationField, getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchDurationPercentiles = async ({ chartType, - setup, + apmEventClient, start, end, environment, @@ -24,7 +24,7 @@ export const fetchDurationPercentiles = async ({ searchMetrics, }: CommonCorrelationsQueryParams & { chartType: LatencyDistributionChartType; - setup: Setup; + apmEventClient: APMEventClient; percents?: number[]; searchMetrics: boolean; }): Promise<{ @@ -63,7 +63,7 @@ export const fetchDurationPercentiles = async ({ }, }, }; - const response = await setup.apmEventClient.search( + const response = await apmEventClient.search( 'get_duration_percentiles', params ); diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_ranges.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_ranges.ts index 1aca4f7be852f..c8f2aae2e9372 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_ranges.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_ranges.ts @@ -8,14 +8,14 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { sumBy } from 'lodash'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; import { Environment } from '../../../../common/environment_rt'; import { getDurationField, getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchDurationRanges = async ({ rangeSteps, - setup, + apmEventClient, start, end, environment, @@ -25,7 +25,7 @@ export const fetchDurationRanges = async ({ searchMetrics, }: { rangeSteps: number[]; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: Environment; @@ -37,7 +37,6 @@ export const fetchDurationRanges = async ({ totalDocCount: number; durationRanges: Array<{ key: number; doc_count: number }>; }> => { - const { apmEventClient } = setup; const durationField = getDurationField(chartType, searchMetrics); // when using metrics data, ensure we filter by docs with the appropriate duration field diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_failed_events_correlation_p_values.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_failed_events_correlation_p_values.ts index 0eddb2b655e3a..405ca6250e5d5 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_failed_events_correlation_p_values.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_failed_events_correlation_p_values.ts @@ -13,13 +13,13 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { EventOutcome } from '../../../../common/event_outcome'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; import { fetchDurationRanges } from './fetch_duration_ranges'; import { getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchFailedEventsCorrelationPValues = async ({ - setup, + apmEventClient, start, end, environment, @@ -28,12 +28,10 @@ export const fetchFailedEventsCorrelationPValues = async ({ rangeSteps, fieldName, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; rangeSteps: number[]; fieldName: string; }) => { - const { apmEventClient } = setup; - const chartType = LatencyDistributionChartType.failedTransactionsCorrelations; const searchMetrics = false; // failed transactions correlations does not search metrics documents const eventType = getEventType(chartType, searchMetrics); @@ -106,7 +104,7 @@ export const fetchFailedEventsCorrelationPValues = async ({ 0.25 * Math.min(Math.max((bucket.score - 13.816) / 101.314, 0), 1); const { durationRanges: histogram } = await fetchDurationRanges({ - setup, + apmEventClient, chartType, start, end, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_field_value_pairs.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_field_value_pairs.ts index e0b12cb8bb9c8..72ffea93e2cae 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_field_value_pairs.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_field_value_pairs.ts @@ -13,11 +13,11 @@ import type { import { TERMS_SIZE } from '../../../../common/correlations/constants'; import { splitAllSettledPromises } from '../utils'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from './get_common_correlations_query'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchFieldValuePairs = async ({ - setup, + apmEventClient, fieldCandidates, eventType, start, @@ -26,12 +26,10 @@ export const fetchFieldValuePairs = async ({ kuery, query, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; fieldCandidates: string[]; eventType: ProcessorEvent; }): Promise<{ fieldValuePairs: FieldValuePair[]; errors: any[] }> => { - const { apmEventClient } = setup; - const { fulfilled: responses, rejected: errors } = splitAllSettledPromises( await Promise.allSettled( fieldCandidates.map(async (fieldName) => { diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts index 72cd6baaefec4..8f2e46b3f4d3f 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts @@ -10,6 +10,7 @@ import type { FailedTransactionsCorrelation } from '../../../../common/correlati import { CommonCorrelationsQueryParams } from '../../../../common/correlations/types'; import { LatencyDistributionChartType } from '../../../../common/latency_distribution_chart_types'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { Setup } from '../../../lib/helpers/setup_request'; import { splitAllSettledPromises, getEventType } from '../utils'; import { fetchDurationHistogramRangeSteps } from './fetch_duration_histogram_range_steps'; @@ -17,6 +18,7 @@ import { fetchFailedEventsCorrelationPValues } from './fetch_failed_events_corre export const fetchPValues = async ({ setup, + apmEventClient, start, end, environment, @@ -27,6 +29,7 @@ export const fetchPValues = async ({ fieldCandidates, }: CommonCorrelationsQueryParams & { setup: Setup; + apmEventClient: APMEventClient; durationMin?: number; durationMax?: number; fieldCandidates: string[]; @@ -36,7 +39,7 @@ export const fetchPValues = async ({ const eventType = getEventType(chartType, searchMetrics); const { rangeSteps } = await fetchDurationHistogramRangeSteps({ - setup, + apmEventClient, chartType, start, end, @@ -52,7 +55,7 @@ export const fetchPValues = async ({ await Promise.allSettled( fieldCandidates.map((fieldName) => fetchFailedEventsCorrelationPValues({ - setup, + apmEventClient, start, end, environment, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts index abb23fbfac0e8..3bfa96423dca4 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts @@ -26,9 +26,11 @@ import { fetchDurationFractions } from './fetch_duration_fractions'; import { fetchDurationHistogramRangeSteps } from './fetch_duration_histogram_range_steps'; import { fetchDurationRanges } from './fetch_duration_ranges'; import { getEventType } from '../utils'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchSignificantCorrelations = async ({ setup, + apmEventClient, start, end, environment, @@ -39,6 +41,7 @@ export const fetchSignificantCorrelations = async ({ fieldValuePairs, }: CommonCorrelationsQueryParams & { setup: Setup; + apmEventClient: APMEventClient; durationMinOverride?: number; durationMaxOverride?: number; fieldValuePairs: FieldValuePair[]; @@ -50,7 +53,7 @@ export const fetchSignificantCorrelations = async ({ const eventType = getEventType(chartType, searchMetrics); const { percentiles: percentilesRecords } = await fetchDurationPercentiles({ - setup, + apmEventClient, chartType, start, end, @@ -69,7 +72,7 @@ export const fetchSignificantCorrelations = async ({ const { expectations, ranges } = computeExpectationsAndRanges(percentiles); const { fractions, totalDocCount } = await fetchDurationFractions({ - setup, + apmEventClient, eventType, start, end, @@ -80,7 +83,7 @@ export const fetchSignificantCorrelations = async ({ }); const { rangeSteps } = await fetchDurationHistogramRangeSteps({ - setup, + apmEventClient, chartType, start, end, @@ -96,7 +99,7 @@ export const fetchSignificantCorrelations = async ({ await Promise.allSettled( fieldValuePairs.map((fieldValuePair) => fetchDurationCorrelationWithHistogram({ - setup, + apmEventClient, chartType, start, end, @@ -142,7 +145,7 @@ export const fetchSignificantCorrelations = async ({ if (latencyCorrelations.length === 0 && fallbackResult) { const { fieldName, fieldValue } = fallbackResult; const { durationRanges: histogram } = await fetchDurationRanges({ - setup, + apmEventClient, chartType, start, end, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_boolean_field_stats.ts b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_boolean_field_stats.ts index 0d03843fd2088..ff1019778ad56 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_boolean_field_stats.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_boolean_field_stats.ts @@ -11,11 +11,11 @@ import { FieldValuePair, } from '../../../../../common/correlations/types'; import { BooleanFieldStats } from '../../../../../common/correlations/field_stats_types'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from '../get_common_correlations_query'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchBooleanFieldStats = async ({ - setup, + apmEventClient, eventType, start, end, @@ -24,12 +24,10 @@ export const fetchBooleanFieldStats = async ({ field, query, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent; field: FieldValuePair; }): Promise => { - const { apmEventClient } = setup; - const { fieldName } = field; const { aggregations } = await apmEventClient.search( diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_field_value_field_stats.ts b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_field_value_field_stats.ts index 9208a8ad682d3..622c7b7d8952e 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_field_value_field_stats.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_field_value_field_stats.ts @@ -14,11 +14,11 @@ import { FieldValueFieldStats, TopValueBucket, } from '../../../../../common/correlations/field_stats_types'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from '../get_common_correlations_query'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchFieldValueFieldStats = async ({ - setup, + apmEventClient, eventType, start, end, @@ -28,11 +28,9 @@ export const fetchFieldValueFieldStats = async ({ field, }: CommonCorrelationsQueryParams & { eventType: ProcessorEvent; - setup: Setup; + apmEventClient: APMEventClient; field: FieldValuePair; }): Promise => { - const { apmEventClient } = setup; - const { aggregations } = await apmEventClient.search( 'get_field_value_field_stats', { diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_fields_stats.ts b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_fields_stats.ts index 2cd1843c6d008..90ed9b3a92950 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_fields_stats.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_fields_stats.ts @@ -16,10 +16,10 @@ import { FieldStats } from '../../../../../common/correlations/field_stats_types import { fetchKeywordFieldStats } from './fetch_keyword_field_stats'; import { fetchNumericFieldStats } from './fetch_numeric_field_stats'; import { fetchBooleanFieldStats } from './fetch_boolean_field_stats'; -import { Setup } from '../../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchFieldsStats = async ({ - setup, + apmEventClient, eventType, start, end, @@ -29,13 +29,12 @@ export const fetchFieldsStats = async ({ fieldsToSample, }: CommonCorrelationsQueryParams & { eventType: ProcessorEvent; - setup: Setup; + apmEventClient: APMEventClient; fieldsToSample: string[]; }): Promise<{ stats: FieldStats[]; errors: any[]; }> => { - const { apmEventClient } = setup; const stats: FieldStats[] = []; const errors: any[] = []; @@ -68,7 +67,7 @@ export const fetchFieldsStats = async ({ case ES_FIELD_TYPES.KEYWORD: case ES_FIELD_TYPES.IP: return fetchKeywordFieldStats({ - setup, + apmEventClient, eventType, start, end, @@ -91,7 +90,7 @@ export const fetchFieldsStats = async ({ case ES_FIELD_TYPES.UNSIGNED_LONG: case ES_FIELD_TYPES.BYTE: return fetchNumericFieldStats({ - setup, + apmEventClient, eventType, start, end, @@ -104,7 +103,7 @@ export const fetchFieldsStats = async ({ break; case ES_FIELD_TYPES.BOOLEAN: return fetchBooleanFieldStats({ - setup, + apmEventClient, eventType, start, end, diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_keyword_field_stats.ts b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_keyword_field_stats.ts index 30e88c0eb8efb..7127db07721e7 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_keyword_field_stats.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_keyword_field_stats.ts @@ -11,11 +11,11 @@ import { FieldValuePair, } from '../../../../../common/correlations/types'; import { KeywordFieldStats } from '../../../../../common/correlations/field_stats_types'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { getCommonCorrelationsQuery } from '../get_common_correlations_query'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export const fetchKeywordFieldStats = async ({ - setup, + apmEventClient, eventType, start, end, @@ -24,12 +24,10 @@ export const fetchKeywordFieldStats = async ({ query, field, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent; field: FieldValuePair; }): Promise => { - const { apmEventClient } = setup; - const body = await apmEventClient.search('get_keyword_field_stats', { apm: { events: [eventType], diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_numeric_field_stats.ts b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_numeric_field_stats.ts index 04b43e09d182a..63bd2a3ea9c8b 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_numeric_field_stats.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/field_stats/fetch_numeric_field_stats.ts @@ -15,11 +15,11 @@ import { CommonCorrelationsQueryParams, FieldValuePair, } from '../../../../../common/correlations/types'; -import { Setup } from '../../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; import { getCommonCorrelationsQuery } from '../get_common_correlations_query'; export const fetchNumericFieldStats = async ({ - setup, + apmEventClient, eventType, start, end, @@ -28,12 +28,10 @@ export const fetchNumericFieldStats = async ({ query, field, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; eventType: ProcessorEvent; field: FieldValuePair; }): Promise => { - const { apmEventClient } = setup; - const { fieldName } = field; const { aggregations } = await apmEventClient.search( diff --git a/x-pack/plugins/apm/server/routes/correlations/route.ts b/x-pack/plugins/apm/server/routes/correlations/route.ts index fd3a405bc7a95..4af95e7a31c1c 100644 --- a/x-pack/plugins/apm/server/routes/correlations/route.ts +++ b/x-pack/plugins/apm/server/routes/correlations/route.ts @@ -30,6 +30,7 @@ import { fetchFieldValuePairs } from './queries/fetch_field_value_pairs'; import { fetchSignificantCorrelations } from './queries/fetch_significant_correlations'; import { fetchFieldsStats } from './queries/field_stats/fetch_fields_stats'; import { fetchPValues } from './queries/fetch_p_values'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const INVALID_LICENSE = i18n.translate('xpack.apm.correlations.license.text', { defaultMessage: @@ -58,7 +59,7 @@ const fieldCandidatesTransactionsRoute = createApmServerRoute({ throw Boom.forbidden(INVALID_LICENSE); } - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { @@ -87,7 +88,7 @@ const fieldCandidatesTransactionsRoute = createApmServerRoute({ ], }, }, - setup, + apmEventClient, }); }, }); @@ -124,7 +125,7 @@ const fieldStatsTransactionsRoute = createApmServerRoute({ throw Boom.forbidden(INVALID_LICENSE); } - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { body: { @@ -140,7 +141,7 @@ const fieldStatsTransactionsRoute = createApmServerRoute({ } = resources.params; return fetchFieldsStats({ - setup, + apmEventClient, eventType: ProcessorEvent.transaction, start, end, @@ -190,7 +191,7 @@ const fieldValueStatsTransactionsRoute = createApmServerRoute({ throw Boom.forbidden(INVALID_LICENSE); } - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { @@ -207,7 +208,7 @@ const fieldValueStatsTransactionsRoute = createApmServerRoute({ } = resources.params; return fetchFieldValueFieldStats({ - setup, + apmEventClient, eventType: ProcessorEvent.transaction, start, end, @@ -262,7 +263,7 @@ const fieldValuePairsTransactionsRoute = createApmServerRoute({ throw Boom.forbidden(INVALID_LICENSE); } - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { body: { @@ -278,7 +279,7 @@ const fieldValuePairsTransactionsRoute = createApmServerRoute({ } = resources.params; return fetchFieldValuePairs({ - setup, + apmEventClient, eventType: ProcessorEvent.transaction, start, end, @@ -334,8 +335,10 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({ totalDocCount: number; fallbackResult?: import('./../../../common/correlations/latency_correlations/types').LatencyCorrelation; }> => { - const setup = await setupRequest(resources); - + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { body: { serviceName, @@ -353,6 +356,7 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({ return fetchSignificantCorrelations({ setup, + apmEventClient, start, end, environment, @@ -402,7 +406,10 @@ const pValuesTransactionsRoute = createApmServerRoute({ ccsWarning: boolean; fallbackResult?: import('./../../../common/correlations/failed_transactions_correlations/types').FailedTransactionsCorrelation; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { body: { @@ -421,6 +428,7 @@ const pValuesTransactionsRoute = createApmServerRoute({ return fetchPValues({ setup, + apmEventClient, start, end, environment, diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts index 65ecb93bcb76e..be38d78fb208f 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts @@ -11,6 +11,7 @@ import * as HistoricalAgentData from '../historical_data/has_historical_agent_da import { DataViewsService } from '@kbn/data-views-plugin/common'; import { APMRouteHandlerResources, APMCore } from '../typings'; import { APMConfig } from '../..'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; function getMockedDataViewService(existingDataViewTitle: string) { return { @@ -44,11 +45,14 @@ const coreMock = { }, } as unknown as APMCore; +const apmEventClientMock = { search: jest.fn() } as unknown as APMEventClient; + describe('createStaticDataView', () => { it(`should not create data view if 'xpack.apm.autocreateApmIndexPattern=false'`, async () => { const dataViewService = getMockedDataViewService('apm-*'); await createStaticDataView({ setup: setupMock, + apmEventClient: apmEventClientMock, resources: { config: { autoCreateApmDataView: false }, } as APMRouteHandlerResources, @@ -67,6 +71,7 @@ describe('createStaticDataView', () => { await createStaticDataView({ setup: setupMock, + apmEventClient: apmEventClientMock, resources: { config: { autoCreateApmDataView: false }, } as APMRouteHandlerResources, @@ -85,6 +90,7 @@ describe('createStaticDataView', () => { await createStaticDataView({ setup: setupMock, + apmEventClient: apmEventClientMock, resources: { core: coreMock, config: { autoCreateApmDataView: true }, @@ -107,6 +113,7 @@ describe('createStaticDataView', () => { await createStaticDataView({ setup: setupMock, + apmEventClient: apmEventClientMock, resources: { core: coreMock, config: { autoCreateApmDataView: true }, @@ -136,6 +143,7 @@ describe('createStaticDataView', () => { await createStaticDataView({ setup: setupMock, + apmEventClient: apmEventClientMock, resources: { core: coreMock, config: { autoCreateApmDataView: true }, diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts index c2310acadcff0..ff25167a0a123 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts @@ -19,6 +19,7 @@ import { getApmDataViewTitle } from './get_apm_data_view_title'; import { APMRouteHandlerResources } from '../typings'; import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export type CreateDataViewResponse = Promise< | { created: boolean; dataView: DataView } @@ -29,10 +30,12 @@ export async function createStaticDataView({ dataViewService, resources, setup, + apmEventClient, }: { dataViewService: DataViewsService; resources: APMRouteHandlerResources; setup: Setup; + apmEventClient: APMEventClient; }): CreateDataViewResponse { const { config } = resources; @@ -50,7 +53,7 @@ export async function createStaticDataView({ // Discover and other apps will throw errors if an data view exists without having matching indices. // The following ensures the data view is only created if APM data is found - const hasData = await hasHistoricalAgentData(setup); + const hasData = await hasHistoricalAgentData(apmEventClient); if (!hasData) { return { diff --git a/x-pack/plugins/apm/server/routes/data_view/route.ts b/x-pack/plugins/apm/server/routes/data_view/route.ts index 6f55f67fc9b4f..8af2a522b7dcd 100644 --- a/x-pack/plugins/apm/server/routes/data_view/route.ts +++ b/x-pack/plugins/apm/server/routes/data_view/route.ts @@ -13,13 +13,17 @@ import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getApmDataViewTitle } from './get_apm_data_view_title'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { setupRequest } from '../../lib/helpers/setup_request'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const staticDataViewRoute = createApmServerRoute({ endpoint: 'POST /internal/apm/data_view/static', options: { tags: ['access:apm'] }, handler: async (resources): CreateDataViewResponse => { const { context, plugins, request } = resources; - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const coreContext = await context.core; const dataViewStart = await plugins.dataViews.start(); @@ -34,6 +38,7 @@ const staticDataViewRoute = createApmServerRoute({ dataViewService, resources, setup, + apmEventClient, }); return res; diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_dependency_latency_distribution.ts b/x-pack/plugins/apm/server/routes/dependencies/get_dependency_latency_distribution.ts index 9f9e356c96dce..150ec8664a246 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_dependency_latency_distribution.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_dependency_latency_distribution.ts @@ -14,12 +14,12 @@ import { import { Environment } from '../../../common/environment_rt'; import { EventOutcome } from '../../../common/event_outcome'; import { LatencyDistributionChartType } from '../../../common/latency_distribution_chart_types'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { getOverallLatencyDistribution } from '../latency_distribution/get_overall_latency_distribution'; import { OverallLatencyDistributionResponse } from '../latency_distribution/types'; export async function getDependencyLatencyDistribution({ - setup, + apmEventClient, dependencyName, spanName, kuery, @@ -28,7 +28,7 @@ export async function getDependencyLatencyDistribution({ end, percentileThreshold, }: { - setup: Setup; + apmEventClient: APMEventClient; dependencyName: string; spanName: string; kuery: string; @@ -40,9 +40,9 @@ export async function getDependencyLatencyDistribution({ allSpansDistribution: OverallLatencyDistributionResponse; failedSpansDistribution: OverallLatencyDistributionResponse; }> { - const commonProps = { + const commonParams = { chartType: LatencyDistributionChartType.dependencyLatency, - setup, + apmEventClient, start, end, environment, @@ -62,11 +62,11 @@ export async function getDependencyLatencyDistribution({ const [allSpansDistribution, failedSpansDistribution] = await Promise.all([ getOverallLatencyDistribution({ - ...commonProps, + ...commonParams, query: commonQuery, }), getOverallLatencyDistribution({ - ...commonProps, + ...commonParams, query: { bool: { filter: [ diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_error_rate_charts_for_dependency.ts b/x-pack/plugins/apm/server/routes/dependencies/get_error_rate_charts_for_dependency.ts index d1f7a655c9f1c..135178aca2ac9 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_error_rate_charts_for_dependency.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_error_rate_charts_for_dependency.ts @@ -17,7 +17,6 @@ import { SPAN_NAME, } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../lib/helpers/metrics'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { @@ -25,11 +24,12 @@ import { getDocumentTypeFilterForServiceDestinationStatistics, getProcessorEventForServiceDestinationStatistics, } from '../../lib/helpers/spans/get_is_using_service_destination_metrics'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getErrorRateChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, environment, @@ -39,7 +39,7 @@ export async function getErrorRateChartsForDependency({ }: { dependencyName: string; spanName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: string; @@ -47,8 +47,6 @@ export async function getErrorRateChartsForDependency({ searchServiceDestinationMetrics: boolean; offset?: string; }) { - const { apmEventClient } = setup; - const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_latency_charts_for_dependency.ts b/x-pack/plugins/apm/server/routes/dependencies/get_latency_charts_for_dependency.ts index 706b0c9d59b9a..14689f9665708 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_latency_charts_for_dependency.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_latency_charts_for_dependency.ts @@ -15,7 +15,6 @@ import { SPAN_NAME, } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../lib/helpers/metrics'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { @@ -24,12 +23,13 @@ import { getLatencyFieldForServiceDestinationStatistics, getProcessorEventForServiceDestinationStatistics, } from '../../lib/helpers/spans/get_is_using_service_destination_metrics'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getLatencyChartsForDependency({ dependencyName, spanName, searchServiceDestinationMetrics, - setup, + apmEventClient, start, end, environment, @@ -39,15 +39,13 @@ export async function getLatencyChartsForDependency({ dependencyName: string; spanName: string; searchServiceDestinationMetrics: boolean; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: string; kuery: string; offset?: string; }) { - const { apmEventClient } = setup; - const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_metadata_for_dependency.ts b/x-pack/plugins/apm/server/routes/dependencies/get_metadata_for_dependency.ts index 1ebfeab5d8a0b..5daf4483f8fd0 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_metadata_for_dependency.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_metadata_for_dependency.ts @@ -9,21 +9,19 @@ import { rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { maybe } from '../../../common/utils/maybe'; import { SPAN_DESTINATION_SERVICE_RESOURCE } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getMetadataForDependency({ - setup, + apmEventClient, dependencyName, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; dependencyName: string; start: number; end: number; }) { - const { apmEventClient } = setup; - const sampleResponse = await apmEventClient.search( 'get_metadata_for_dependency', { diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_throughput_charts_for_dependency.ts b/x-pack/plugins/apm/server/routes/dependencies/get_throughput_charts_for_dependency.ts index 63c72f6c460d8..6ba07907666be 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_throughput_charts_for_dependency.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_throughput_charts_for_dependency.ts @@ -15,7 +15,6 @@ import { SPAN_NAME, } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { getBucketSize } from '../../lib/helpers/get_bucket_size'; import { @@ -23,11 +22,12 @@ import { getDocumentTypeFilterForServiceDestinationStatistics, getProcessorEventForServiceDestinationStatistics, } from '../../lib/helpers/spans/get_is_using_service_destination_metrics'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getThroughputChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, environment, @@ -37,7 +37,7 @@ export async function getThroughputChartsForDependency({ }: { dependencyName: string; spanName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: string; @@ -45,8 +45,6 @@ export async function getThroughputChartsForDependency({ searchServiceDestinationMetrics: boolean; offset?: string; }) { - const { apmEventClient } = setup; - const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependencies.ts b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependencies.ts index 08e2f6183303e..d8ee73af18e87 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependencies.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependencies.ts @@ -10,10 +10,10 @@ import { NodeType } from '../../../common/connections'; import { environmentQuery } from '../../../common/utils/environment_query'; import { getConnectionStats } from '../../lib/connections/get_connection_stats'; import { getConnectionStatsItemsWithRelativeImpact } from '../../lib/connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTopDependencies({ - setup, + apmEventClient, start, end, numBuckets, @@ -21,7 +21,7 @@ export async function getTopDependencies({ offset, kuery, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; numBuckets: number; @@ -30,7 +30,7 @@ export async function getTopDependencies({ kuery: string; }) { const statsItems = await getConnectionStats({ - setup, + apmEventClient, start, end, numBuckets, diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_operations.ts b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_operations.ts index 3c688f9aaa488..b2e4c44a730fb 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_operations.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_operations.ts @@ -24,13 +24,13 @@ import { environmentQuery } from '../../../common/utils/environment_query'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { calculateThroughputWithRange } from '../../lib/helpers/calculate_throughput'; import { getBucketSizeForAggregatedTransactions } from '../../lib/helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../../lib/helpers/setup_request'; import { getDocumentTypeFilterForServiceDestinationStatistics, getLatencyFieldForServiceDestinationStatistics, getProcessorEventForServiceDestinationStatistics, } from '../../lib/helpers/spans/get_is_using_service_destination_metrics'; import { calculateImpactBuilder } from '../traces/calculate_impact_builder'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; const MAX_NUM_OPERATIONS = 500; @@ -47,7 +47,7 @@ export interface DependencyOperation { } export async function getTopDependencyOperations({ - setup, + apmEventClient, dependencyName, start, end, @@ -56,7 +56,7 @@ export async function getTopDependencyOperations({ kuery, searchServiceDestinationMetrics, }: { - setup: Setup; + apmEventClient: APMEventClient; dependencyName: string; start: number; end: number; @@ -65,8 +65,6 @@ export async function getTopDependencyOperations({ kuery: string; searchServiceDestinationMetrics: boolean; }) { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset, offsetInMs } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_spans.ts b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_spans.ts index 6b4998517735a..5a2df933c7dba 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_spans.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_top_dependency_spans.ts @@ -30,7 +30,7 @@ import { Environment } from '../../../common/environment_rt'; import { EventOutcome } from '../../../common/event_outcome'; import { environmentQuery } from '../../../common/utils/environment_query'; import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; const MAX_NUM_SPANS = 1000; @@ -48,7 +48,7 @@ export interface DependencySpan { } export async function getTopDependencySpans({ - setup, + apmEventClient, dependencyName, spanName, start, @@ -58,7 +58,7 @@ export async function getTopDependencySpans({ sampleRangeFrom, sampleRangeTo, }: { - setup: Setup; + apmEventClient: APMEventClient; dependencyName: string; spanName: string; start: number; @@ -68,8 +68,6 @@ export async function getTopDependencySpans({ sampleRangeFrom?: number; sampleRangeTo?: number; }): Promise { - const { apmEventClient } = setup; - const spans = ( await apmEventClient.search('get_top_dependency_spans', { apm: { diff --git a/x-pack/plugins/apm/server/routes/dependencies/get_upstream_services_for_dependency.ts b/x-pack/plugins/apm/server/routes/dependencies/get_upstream_services_for_dependency.ts index 4d620619e2eb1..8f2710cbc972f 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/get_upstream_services_for_dependency.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/get_upstream_services_for_dependency.ts @@ -10,10 +10,10 @@ import { SPAN_DESTINATION_SERVICE_RESOURCE } from '../../../common/elasticsearch import { environmentQuery } from '../../../common/utils/environment_query'; import { getConnectionStats } from '../../lib/connections/get_connection_stats'; import { getConnectionStatsItemsWithRelativeImpact } from '../../lib/connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getUpstreamServicesForDependency({ - setup, + apmEventClient, start, end, dependencyName, @@ -22,7 +22,7 @@ export async function getUpstreamServicesForDependency({ environment, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; dependencyName: string; @@ -32,7 +32,7 @@ export async function getUpstreamServicesForDependency({ offset?: string; }) { const statsItems = await getConnectionStats({ - setup, + apmEventClient, start, end, filter: [ diff --git a/x-pack/plugins/apm/server/routes/dependencies/route.ts b/x-pack/plugins/apm/server/routes/dependencies/route.ts index 1ba2e92eee57a..964e1ed95834a 100644 --- a/x-pack/plugins/apm/server/routes/dependencies/route.ts +++ b/x-pack/plugins/apm/server/routes/dependencies/route.ts @@ -7,7 +7,6 @@ import * as t from 'io-ts'; import { toBooleanRt, toNumberRt } from '@kbn/io-ts-utils'; -import { setupRequest } from '../../lib/helpers/setup_request'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getMetadataForDependency } from './get_metadata_for_dependency'; @@ -28,6 +27,7 @@ import { DependencySpan, getTopDependencySpans, } from './get_top_dependency_spans'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const topDependenciesRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/dependencies/top_dependencies', @@ -100,11 +100,11 @@ const topDependenciesRoute = createApmServerRoute({ location: import('./../../../common/connections').Node; }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { environment, offset, numBuckets, kuery, start, end } = resources.params.query; - const opts = { setup, start, end, numBuckets, environment, kuery }; + const opts = { apmEventClient, start, end, numBuckets, environment, kuery }; const [currentDependencies, previousDependencies] = await Promise.all([ getTopDependencies(opts), @@ -198,7 +198,7 @@ const upstreamServicesForDependencyRoute = createApmServerRoute({ location: import('./../../../common/connections').Node; }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { dependencyName, @@ -213,7 +213,7 @@ const upstreamServicesForDependencyRoute = createApmServerRoute({ const opts = { dependencyName, - setup, + apmEventClient, start, end, numBuckets, @@ -264,14 +264,14 @@ const dependencyMetadataRoute = createApmServerRoute({ ): Promise<{ metadata: { spanType: string | undefined; spanSubtype: string | undefined }; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { dependencyName, start, end } = params.query; const metadata = await getMetadataForDependency({ dependencyName, - setup, + apmEventClient, start, end, }); @@ -304,7 +304,7 @@ const dependencyLatencyChartsRoute = createApmServerRoute({ currentTimeseries: Array<{ x: number; y: number }>; comparisonTimeseries: Array<{ x: number; y: number }> | null; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { dependencyName, @@ -322,7 +322,7 @@ const dependencyLatencyChartsRoute = createApmServerRoute({ dependencyName, spanName, searchServiceDestinationMetrics, - setup, + apmEventClient, start, end, kuery, @@ -333,7 +333,7 @@ const dependencyLatencyChartsRoute = createApmServerRoute({ dependencyName, spanName, searchServiceDestinationMetrics, - setup, + apmEventClient, start, end, kuery, @@ -371,7 +371,7 @@ const dependencyThroughputChartsRoute = createApmServerRoute({ currentTimeseries: Array<{ x: number; y: number | null }>; comparisonTimeseries: Array<{ x: number; y: number | null }> | null; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { dependencyName, @@ -388,7 +388,7 @@ const dependencyThroughputChartsRoute = createApmServerRoute({ getThroughputChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, kuery, @@ -399,7 +399,7 @@ const dependencyThroughputChartsRoute = createApmServerRoute({ ? getThroughputChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, kuery, @@ -438,7 +438,7 @@ const dependencyFailedTransactionRateChartsRoute = createApmServerRoute({ currentTimeseries: Array<{ x: number; y: number }>; comparisonTimeseries: Array<{ x: number; y: number }> | null; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { dependencyName, @@ -455,7 +455,7 @@ const dependencyFailedTransactionRateChartsRoute = createApmServerRoute({ getErrorRateChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, kuery, @@ -466,7 +466,7 @@ const dependencyFailedTransactionRateChartsRoute = createApmServerRoute({ ? getErrorRateChartsForDependency({ dependencyName, spanName, - setup, + apmEventClient, start, end, kuery, @@ -501,7 +501,7 @@ const dependencyOperationsRoute = createApmServerRoute({ handler: async ( resources ): Promise<{ operations: DependencyOperation[] }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { @@ -516,7 +516,7 @@ const dependencyOperationsRoute = createApmServerRoute({ } = resources.params; const operations = await getTopDependencyOperations({ - setup, + apmEventClient, dependencyName, start, end, @@ -553,7 +553,7 @@ const dependencyLatencyDistributionChartsRoute = createApmServerRoute({ allSpansDistribution: OverallLatencyDistributionResponse; failedSpansDistribution: OverallLatencyDistributionResponse; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { dependencyName, @@ -566,7 +566,7 @@ const dependencyLatencyDistributionChartsRoute = createApmServerRoute({ } = params.query; return getDependencyLatencyDistribution({ - setup, + apmEventClient, dependencyName, spanName, percentileThreshold, @@ -593,7 +593,7 @@ const topDependencySpansRoute = createApmServerRoute({ ]), }), handler: async (resources): Promise<{ spans: DependencySpan[] }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { @@ -609,7 +609,7 @@ const topDependencySpansRoute = createApmServerRoute({ } = resources.params; const spans = await getTopDependencySpans({ - setup, + apmEventClient, dependencyName, spanName, start, diff --git a/x-pack/plugins/apm/server/routes/environments/get_all_environments.test.ts b/x-pack/plugins/apm/server/routes/environments/get_all_environments.test.ts index 0f27839d94048..dd8dcfb31ba61 100644 --- a/x-pack/plugins/apm/server/routes/environments/get_all_environments.test.ts +++ b/x-pack/plugins/apm/server/routes/environments/get_all_environments.test.ts @@ -19,11 +19,11 @@ describe('getAllEnvironments', () => { }); it('fetches all environments', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getAllEnvironments({ searchAggregatedTransactions: false, serviceName: 'test', - setup, + apmEventClient, size: 50, }) ); @@ -32,12 +32,12 @@ describe('getAllEnvironments', () => { }); it('fetches all environments with includeMissing', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getAllEnvironments({ includeMissing: true, searchAggregatedTransactions: false, serviceName: 'test', - setup, + apmEventClient, size: 50, }) ); diff --git a/x-pack/plugins/apm/server/routes/environments/get_all_environments.ts b/x-pack/plugins/apm/server/routes/environments/get_all_environments.ts index 6cac07f1ea9be..8cd7c14a0d629 100644 --- a/x-pack/plugins/apm/server/routes/environments/get_all_environments.ts +++ b/x-pack/plugins/apm/server/routes/environments/get_all_environments.ts @@ -7,13 +7,13 @@ import { termQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../lib/helpers/setup_request'; import { SERVICE_NAME, SERVICE_ENVIRONMENT, } from '../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; /** * This is used for getting *all* environments, and does not filter by range. @@ -23,21 +23,19 @@ export async function getAllEnvironments({ includeMissing = false, searchAggregatedTransactions, serviceName, - setup, + apmEventClient, size, }: { includeMissing?: boolean; searchAggregatedTransactions: boolean; serviceName?: string; - setup: Setup; + apmEventClient: APMEventClient; size: number; }) { const operationName = serviceName ? 'get_all_environments_for_service' : 'get_all_environments_for_all_services'; - const { apmEventClient } = setup; - const params = { apm: { events: [ diff --git a/x-pack/plugins/apm/server/routes/environments/get_environments.test.ts b/x-pack/plugins/apm/server/routes/environments/get_environments.test.ts index 472fd9d226e35..21daac57a7521 100644 --- a/x-pack/plugins/apm/server/routes/environments/get_environments.test.ts +++ b/x-pack/plugins/apm/server/routes/environments/get_environments.test.ts @@ -19,9 +19,9 @@ describe('getEnvironments', () => { }); it('fetches environments', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getEnvironments({ - setup, + apmEventClient, serviceName: 'foo', searchAggregatedTransactions: false, size: 50, @@ -34,9 +34,9 @@ describe('getEnvironments', () => { }); it('fetches environments without a service name', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getEnvironments({ - setup, + apmEventClient, searchAggregatedTransactions: false, size: 50, start: 0, diff --git a/x-pack/plugins/apm/server/routes/environments/get_environments.ts b/x-pack/plugins/apm/server/routes/environments/get_environments.ts index dbd0eb5a9d9c6..e8a3abace204e 100644 --- a/x-pack/plugins/apm/server/routes/environments/get_environments.ts +++ b/x-pack/plugins/apm/server/routes/environments/get_environments.ts @@ -13,8 +13,8 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; -import { Setup } from '../../lib/helpers/setup_request'; import { Environment } from '../../../common/environment_rt'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; /** * This is used for getting the list of environments for the environments selector, @@ -23,12 +23,12 @@ import { Environment } from '../../../common/environment_rt'; export async function getEnvironments({ searchAggregatedTransactions, serviceName, - setup, + apmEventClient, size, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; serviceName?: string; searchAggregatedTransactions: boolean; size: number; @@ -39,8 +39,6 @@ export async function getEnvironments({ ? 'get_environments_for_service' : 'get_environments'; - const { apmEventClient } = setup; - const params = { apm: { events: [ diff --git a/x-pack/plugins/apm/server/routes/environments/route.ts b/x-pack/plugins/apm/server/routes/environments/route.ts index 4a7755230754c..6b0225caa9b36 100644 --- a/x-pack/plugins/apm/server/routes/environments/route.ts +++ b/x-pack/plugins/apm/server/routes/environments/route.ts @@ -12,6 +12,7 @@ import { setupRequest } from '../../lib/helpers/setup_request'; import { getEnvironments } from './get_environments'; import { rangeRt } from '../default_api_types'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const environmentsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/environments', @@ -36,11 +37,14 @@ const environmentsRoute = createApmServerRoute({ > >; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { context, params } = resources; const { serviceName, start, end } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -51,7 +55,7 @@ const environmentsRoute = createApmServerRoute({ maxSuggestions ); const environments = await getEnvironments({ - setup, + apmEventClient, serviceName, searchAggregatedTransactions, size, diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts index 6d460e5d42d7b..4a3fc6d969cd0 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts @@ -6,7 +6,6 @@ */ import { getBuckets } from './get_buckets'; -import { APMConfig } from '../../..'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; describe('get buckets', () => { @@ -29,30 +28,9 @@ describe('get buckets', () => { serviceName: 'myServiceName', bucketSize: 10, kuery: '', - setup: { - apmEventClient: { - search: clientSpy, - } as any, - internalClient: { - search: clientSpy, - } as any, - config: new Proxy( - {}, - { - get: () => 'myIndex', - } - ) as APMConfig, - indices: { - sourcemap: 'apm-*', - error: 'apm-*', - onboarding: 'apm-*', - span: 'apm-*', - transaction: 'apm-*', - metric: 'apm-*', - apmAgentConfigurationIndex: '.apm-agent-configuration', - apmCustomLinkIndex: '.apm-custom-link', - }, - }, + apmEventClient: { + search: clientSpy, + } as any, start: 1528113600000, end: 1528977600000, }); diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts index bd1b070da90d7..770305df2aab2 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts @@ -16,7 +16,7 @@ import { SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getBuckets({ environment, @@ -24,7 +24,7 @@ export async function getBuckets({ serviceName, groupId, bucketSize, - setup, + apmEventClient, start, end, }: { @@ -33,12 +33,10 @@ export async function getBuckets({ serviceName: string; groupId?: string; bucketSize: number; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { apm: { events: [ProcessorEvent.error], diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/get_distribution.ts b/x-pack/plugins/apm/server/routes/errors/distribution/get_distribution.ts index f4df8ab5b7dfb..9d7116a03226d 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/get_distribution.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/get_distribution.ts @@ -6,10 +6,10 @@ */ import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; -import { Setup } from '../../../lib/helpers/setup_request'; import { BUCKET_TARGET_COUNT } from '../../transactions/constants'; import { getBuckets } from './get_buckets'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; function getBucketSize({ start, end }: { start: number; end: number }) { return Math.floor((end - start) / BUCKET_TARGET_COUNT); @@ -20,7 +20,7 @@ export async function getErrorDistribution({ kuery, serviceName, groupId, - setup, + apmEventClient, start, end, offset, @@ -29,7 +29,7 @@ export async function getErrorDistribution({ kuery: string; serviceName: string; groupId?: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; offset?: string; @@ -50,7 +50,7 @@ export async function getErrorDistribution({ kuery, serviceName, groupId, - setup, + apmEventClient, bucketSize, }; const currentPeriodPromise = getBuckets({ diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/queries.test.ts b/x-pack/plugins/apm/server/routes/errors/distribution/queries.test.ts index bda8abc1659eb..cbb606b8a0c96 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/queries.test.ts @@ -20,10 +20,10 @@ describe('error distribution queries', () => { }); it('fetches an error distribution', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getErrorDistribution({ serviceName: 'serviceName', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -35,11 +35,11 @@ describe('error distribution queries', () => { }); it('fetches an error distribution with a group id', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getErrorDistribution({ serviceName: 'serviceName', groupId: 'foo', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, diff --git a/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts b/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts index d126057f515be..70ee012635b01 100644 --- a/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts +++ b/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts @@ -26,16 +26,16 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getBucketSize } from '../../../lib/helpers/get_bucket_size'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; async function getTopErroneousTransactions({ environment, kuery, serviceName, groupId, - setup, + apmEventClient, start, end, numBuckets, @@ -45,14 +45,12 @@ async function getTopErroneousTransactions({ kuery: string; serviceName: string; groupId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; numBuckets: number; offset?: string; }) { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset, offsetInMs } = getOffsetInMs({ start, end, @@ -132,7 +130,7 @@ async function getTopErroneousTransactions({ export async function getTopErroneousTransactionsPeriods({ kuery, serviceName, - setup, + apmEventClient, numBuckets, groupId, environment, @@ -142,7 +140,7 @@ export async function getTopErroneousTransactionsPeriods({ }: { kuery: string; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; numBuckets: number; groupId: string; environment: string; @@ -155,7 +153,7 @@ export async function getTopErroneousTransactionsPeriods({ environment, kuery, serviceName, - setup, + apmEventClient, numBuckets, groupId, start, @@ -166,7 +164,7 @@ export async function getTopErroneousTransactionsPeriods({ environment, kuery, serviceName, - setup, + apmEventClient, numBuckets, groupId, start, diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_detailed_statistics.ts index 325b134902c86..30720c2d799c3 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_detailed_statistics.ts @@ -20,13 +20,13 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { getBucketSize } from '../../../lib/helpers/get_bucket_size'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getErrorGroupDetailedStatistics({ kuery, serviceName, - setup, + apmEventClient, numBuckets, groupIds, environment, @@ -36,7 +36,7 @@ export async function getErrorGroupDetailedStatistics({ }: { kuery: string; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; numBuckets: number; groupIds: string[]; environment: string; @@ -44,8 +44,6 @@ export async function getErrorGroupDetailedStatistics({ end: number; offset?: string; }): Promise> { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -124,7 +122,7 @@ export async function getErrorGroupDetailedStatistics({ export async function getErrorGroupPeriods({ kuery, serviceName, - setup, + apmEventClient, numBuckets, groupIds, environment, @@ -134,7 +132,7 @@ export async function getErrorGroupPeriods({ }: { kuery: string; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; numBuckets: number; groupIds: string[]; environment: string; @@ -146,7 +144,7 @@ export async function getErrorGroupPeriods({ environment, kuery, serviceName, - setup, + apmEventClient, numBuckets, groupIds, }; diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts index c27d30a253f28..f4d2fcff4a402 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts @@ -25,12 +25,12 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { getErrorName } from '../../../lib/helpers/get_error_name'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getErrorGroupMainStatistics({ kuery, serviceName, - setup, + apmEventClient, environment, sortField, sortDirection = 'desc', @@ -42,7 +42,7 @@ export async function getErrorGroupMainStatistics({ }: { kuery: string; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; environment: string; sortField?: string; sortDirection?: 'asc' | 'desc'; @@ -52,8 +52,6 @@ export async function getErrorGroupMainStatistics({ transactionName?: string; transactionType?: string; }) { - const { apmEventClient } = setup; - // sort buckets by last occurrence of error const sortByLatestOccurrence = sortField === 'lastSeen'; diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample.ts index d5a8b8a5ac650..744db1c9c21b8 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample.ts @@ -15,14 +15,14 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { getTransaction } from '../../transactions/get_transaction'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getErrorGroupSample({ environment, kuery, serviceName, groupId, - setup, + apmEventClient, start, end, }: { @@ -30,12 +30,10 @@ export async function getErrorGroupSample({ kuery: string; serviceName: string; groupId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { apm: { events: [ProcessorEvent.error as const], @@ -72,7 +70,7 @@ export async function getErrorGroupSample({ transaction = await getTransaction({ transactionId, traceId, - setup, + apmEventClient, start, end, }); diff --git a/x-pack/plugins/apm/server/routes/errors/queries.test.ts b/x-pack/plugins/apm/server/routes/errors/queries.test.ts index 7cb84db0d7862..080f175c2d5e8 100644 --- a/x-pack/plugins/apm/server/routes/errors/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/errors/queries.test.ts @@ -21,11 +21,11 @@ describe('error queries', () => { }); it('fetches a single error group', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getErrorGroupSample({ groupId: 'groupId', serviceName: 'serviceName', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -37,12 +37,12 @@ describe('error queries', () => { }); it('fetches multiple error groups', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getErrorGroupMainStatistics({ sortDirection: 'asc', sortField: 'foo', serviceName: 'serviceName', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -54,12 +54,12 @@ describe('error queries', () => { }); it('fetches multiple error groups when sortField = lastSeen', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getErrorGroupMainStatistics({ sortDirection: 'asc', sortField: 'lastSeen', serviceName: 'serviceName', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, diff --git a/x-pack/plugins/apm/server/routes/errors/route.ts b/x-pack/plugins/apm/server/routes/errors/route.ts index 17faea2765daa..5bb3bda954ee5 100644 --- a/x-pack/plugins/apm/server/routes/errors/route.ts +++ b/x-pack/plugins/apm/server/routes/errors/route.ts @@ -9,13 +9,13 @@ import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getErrorDistribution } from './distribution/get_distribution'; -import { setupRequest } from '../../lib/helpers/setup_request'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; import { getErrorGroupMainStatistics } from './get_error_groups/get_error_group_main_statistics'; import { getErrorGroupPeriods } from './get_error_groups/get_error_group_detailed_statistics'; import { getErrorGroupSample } from './get_error_groups/get_error_group_sample'; import { offsetRt } from '../../../common/comparison_rt'; import { getTopErroneousTransactionsPeriods } from './erroneous_transactions/get_top_erroneous_transactions'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const errorsMainStatisticsRoute = createApmServerRoute({ endpoint: @@ -49,7 +49,7 @@ const errorsMainStatisticsRoute = createApmServerRoute({ }>; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { serviceName } = params.path; const { environment, kuery, sortField, sortDirection, start, end } = params.query; @@ -60,7 +60,7 @@ const errorsMainStatisticsRoute = createApmServerRoute({ serviceName, sortField, sortDirection, - setup, + apmEventClient, start, end, }); @@ -102,7 +102,7 @@ const errorsMainStatisticsByTransactionNameRoute = createApmServerRoute({ }>; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { serviceName } = params.path; const { environment, @@ -118,7 +118,7 @@ const errorsMainStatisticsByTransactionNameRoute = createApmServerRoute({ environment, kuery, serviceName, - setup, + apmEventClient, start, end, maxNumberOfErrorGroups, @@ -164,7 +164,7 @@ const errorsDetailedStatisticsRoute = createApmServerRoute({ groupId: string; }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { @@ -177,7 +177,7 @@ const errorsDetailedStatisticsRoute = createApmServerRoute({ environment, kuery, serviceName, - setup, + apmEventClient, numBuckets, groupIds, start, @@ -207,7 +207,7 @@ const errorGroupsRoute = createApmServerRoute({ occurrencesCount: number; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { serviceName, groupId } = params.path; const { environment, kuery, start, end } = params.query; @@ -216,7 +216,7 @@ const errorGroupsRoute = createApmServerRoute({ groupId, kuery, serviceName, - setup, + apmEventClient, start, end, }); @@ -250,7 +250,7 @@ const errorDistributionRoute = createApmServerRoute({ }>; bucketSize: number; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { environment, kuery, groupId, start, end, offset } = params.query; @@ -259,7 +259,7 @@ const errorDistributionRoute = createApmServerRoute({ kuery, serviceName, groupId, - setup, + apmEventClient, start, end, offset, @@ -298,7 +298,7 @@ const topErroneousTransactionsRoute = createApmServerRoute({ }>; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { path: { serviceName, groupId }, @@ -310,7 +310,7 @@ const topErroneousTransactionsRoute = createApmServerRoute({ groupId, kuery, serviceName, - setup, + apmEventClient, start, end, numBuckets, diff --git a/x-pack/plugins/apm/server/routes/event_metadata/route.ts b/x-pack/plugins/apm/server/routes/event_metadata/route.ts index a057be53ef43f..02709d2c499e5 100644 --- a/x-pack/plugins/apm/server/routes/event_metadata/route.ts +++ b/x-pack/plugins/apm/server/routes/event_metadata/route.ts @@ -9,7 +9,7 @@ import * as t from 'io-ts'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getEventMetadata } from './get_event_metadata'; import { processorEventRt } from '../../../common/processor_event'; -import { setupRequest } from '../../lib/helpers/setup_request'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const eventMetadataRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', @@ -23,14 +23,14 @@ const eventMetadataRoute = createApmServerRoute({ handler: async ( resources ): Promise<{ metadata: Partial> }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { path: { processorEvent, id }, } = resources.params; const metadata = await getEventMetadata({ - apmEventClient: setup.apmEventClient, + apmEventClient, processorEvent, id, }); diff --git a/x-pack/plugins/apm/server/routes/fallback_to_transactions/route.ts b/x-pack/plugins/apm/server/routes/fallback_to_transactions/route.ts index 60355b5447b85..2e056df7ee891 100644 --- a/x-pack/plugins/apm/server/routes/fallback_to_transactions/route.ts +++ b/x-pack/plugins/apm/server/routes/fallback_to_transactions/route.ts @@ -10,6 +10,7 @@ import { getIsUsingTransactionEvents } from '../../lib/helpers/transactions/get_ import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { kueryRt, rangeRt } from '../default_api_types'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const fallbackToTransactionsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/fallback_to_transactions', @@ -18,7 +19,10 @@ const fallbackToTransactionsRoute = createApmServerRoute({ }), options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ fallbackToTransactions: boolean }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params: { query: { kuery, start, end }, @@ -26,7 +30,8 @@ const fallbackToTransactionsRoute = createApmServerRoute({ } = resources; return { fallbackToTransactions: await getIsUsingTransactionEvents({ - setup, + config: setup.config, + apmEventClient, kuery, start, end, diff --git a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts index e269e036396fd..befd25abb22f2 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts @@ -6,12 +6,10 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; // Note: this logic is duplicated in tutorials/apm/envs/on_prem -export async function hasHistoricalAgentData(setup: Setup) { - const { apmEventClient } = setup; - +export async function hasHistoricalAgentData(apmEventClient: APMEventClient) { const params = { terminate_after: 1, apm: { diff --git a/x-pack/plugins/apm/server/routes/historical_data/route.ts b/x-pack/plugins/apm/server/routes/historical_data/route.ts index e9836df61acbf..204af4bb05b03 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/route.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { setupRequest } from '../../lib/helpers/setup_request'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { hasHistoricalAgentData } from './has_historical_agent_data'; @@ -13,8 +13,8 @@ const hasDataRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/has_data', options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ hasData: boolean }> => { - const setup = await setupRequest(resources); - const hasData = await hasHistoricalAgentData(setup); + const apmEventClient = await getApmEventClient(resources); + const hasData = await hasHistoricalAgentData(apmEventClient); return { hasData }; }, }); diff --git a/x-pack/plugins/apm/server/routes/infrastructure/get_infrastructure_data.ts b/x-pack/plugins/apm/server/routes/infrastructure/get_infrastructure_data.ts index 0d79901efbc72..73c9732335c10 100644 --- a/x-pack/plugins/apm/server/routes/infrastructure/get_infrastructure_data.ts +++ b/x-pack/plugins/apm/server/routes/infrastructure/get_infrastructure_data.ts @@ -7,7 +7,6 @@ import { rangeQuery, kqlQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../lib/helpers/setup_request'; import { environmentQuery } from '../../../common/utils/environment_query'; import { SERVICE_NAME, @@ -15,24 +14,23 @@ import { HOST_HOSTNAME, KUBERNETES_POD_NAME, } from '../../../common/elasticsearch_fieldnames'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export const getInfrastructureData = async ({ kuery, serviceName, environment, - setup, + apmEventClient, start, end, }: { kuery: string; serviceName: string; environment: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) => { - const { apmEventClient } = setup; - const response = await apmEventClient.search('get_service_infrastructure', { apm: { events: [ProcessorEvent.metric], diff --git a/x-pack/plugins/apm/server/routes/infrastructure/route.ts b/x-pack/plugins/apm/server/routes/infrastructure/route.ts index 678f380bc4fd8..151ed589396ce 100644 --- a/x-pack/plugins/apm/server/routes/infrastructure/route.ts +++ b/x-pack/plugins/apm/server/routes/infrastructure/route.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; -import { setupRequest } from '../../lib/helpers/setup_request'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; import { getInfrastructureData } from './get_infrastructure_data'; import { getContainerHostNames } from './get_host_names'; @@ -29,7 +29,7 @@ const infrastructureRoute = createApmServerRoute({ hostNames: string[]; podNames: string[]; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const infraMetricsClient = createInfraMetricsClient(resources); const { params } = resources; @@ -40,7 +40,7 @@ const infrastructureRoute = createApmServerRoute({ } = params; const infrastructureData = await getInfrastructureData({ - setup, + apmEventClient, serviceName, environment, kuery, diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts b/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts index 206deb8a32d15..39ff3cf622dfd 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts @@ -7,21 +7,17 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Environment } from '../../../common/environment_rt'; - -import { Setup } from '../../lib/helpers/setup_request'; - import { withApmSpan } from '../../utils/with_apm_span'; - import { fetchDurationRanges } from '../correlations/queries/fetch_duration_ranges'; import { fetchDurationHistogramRangeSteps } from '../correlations/queries/fetch_duration_histogram_range_steps'; - import { getPercentileThresholdValue } from './get_percentile_threshold_value'; import type { OverallLatencyDistributionResponse } from './types'; import { LatencyDistributionChartType } from '../../../common/latency_distribution_chart_types'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getOverallLatencyDistribution({ chartType, - setup, + apmEventClient, start, end, environment, @@ -33,7 +29,7 @@ export async function getOverallLatencyDistribution({ searchMetrics, }: { chartType: LatencyDistributionChartType; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: Environment; @@ -51,7 +47,7 @@ export async function getOverallLatencyDistribution({ overallLatencyDistribution.percentileThresholdValue = await getPercentileThresholdValue({ chartType, - setup, + apmEventClient, start, end, environment, @@ -70,7 +66,7 @@ export async function getOverallLatencyDistribution({ const { durationMin, durationMax, rangeSteps } = await fetchDurationHistogramRangeSteps({ chartType, - setup, + apmEventClient, start, end, environment, @@ -88,7 +84,7 @@ export async function getOverallLatencyDistribution({ // #3: get histogram chart data const { totalDocCount, durationRanges } = await fetchDurationRanges({ chartType, - setup, + apmEventClient, start, end, environment, diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/get_percentile_threshold_value.ts b/x-pack/plugins/apm/server/routes/latency_distribution/get_percentile_threshold_value.ts index e24fefa572882..bb6b65c4a1735 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/get_percentile_threshold_value.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/get_percentile_threshold_value.ts @@ -7,11 +7,11 @@ import { CommonCorrelationsQueryParams } from '../../../common/correlations/types'; import { LatencyDistributionChartType } from '../../../common/latency_distribution_chart_types'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { fetchDurationPercentiles } from '../correlations/queries/fetch_duration_percentiles'; export async function getPercentileThresholdValue({ - setup, + apmEventClient, chartType, start, end, @@ -21,13 +21,13 @@ export async function getPercentileThresholdValue({ percentileThreshold, searchMetrics, }: CommonCorrelationsQueryParams & { - setup: Setup; + apmEventClient: APMEventClient; chartType: LatencyDistributionChartType; percentileThreshold: number; searchMetrics: boolean; }) { const durationPercentiles = await fetchDurationPercentiles({ - setup, + apmEventClient, chartType, start, end, diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts index ac0e65abe3157..d2e6dee2795e7 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts @@ -23,6 +23,7 @@ import { latencyDistributionChartTypeRt, LatencyDistributionChartType, } from '../../../common/latency_distribution_chart_types'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const latencyOverallTransactionDistributionRoute = createApmServerRoute({ endpoint: 'POST /internal/apm/latency/overall_distribution/transactions', @@ -54,7 +55,10 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ handler: async ( resources ): Promise => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { environment, @@ -75,7 +79,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ const searchAggregatedTransactions = chartType === LatencyDistributionChartType.transactionLatency ? await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -83,7 +88,7 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ : false; return getOverallLatencyDistribution({ - setup, + apmEventClient, chartType, environment, kuery, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/default.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/default.ts index b4e95d5217daa..d228cdd352981 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/default.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/default.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMConfig } from '../../..'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { getCPUChartData } from './shared/cpu'; import { getMemoryChartData } from './shared/memory'; @@ -13,19 +14,37 @@ export function getDefaultMetricsCharts({ environment, kuery, serviceName, - setup, + config, + apmEventClient, start, end, }: { environment: string; kuery: string; serviceName: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; start: number; end: number; }) { return Promise.all([ - getCPUChartData({ environment, kuery, setup, serviceName, start, end }), - getMemoryChartData({ environment, kuery, setup, serviceName, start, end }), + getCPUChartData({ + environment, + kuery, + config, + apmEventClient, + serviceName, + start, + end, + }), + getMemoryChartData({ + environment, + kuery, + config, + apmEventClient, + serviceName, + start, + end, + }), ]); } diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts index 8b3fcbfe5ce88..d6e60cf713d54 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts @@ -9,6 +9,7 @@ import { METRIC_JAVA_GC_COUNT, METRIC_JAVA_GC_TIME, } from '../../../../../../common/elasticsearch_fieldnames'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; import { Setup } from '../../../../../lib/helpers/setup_request'; import { ChartBase } from '../../../types'; @@ -50,9 +51,11 @@ describe('fetchAndTransformGcMetrics', () => { }, }; const setup = { - apmEventClient: { search: () => Promise.resolve(response) }, config: { 'xpack.gc.metricsInterval': 0 }, } as unknown as Setup; + const apmEventClient = { + search: () => Promise.resolve(response), + } as unknown as APMEventClient; const fieldName = METRIC_JAVA_GC_TIME; const { series } = await fetchAndTransformGcMetrics({ @@ -61,7 +64,8 @@ describe('fetchAndTransformGcMetrics', () => { fieldName, kuery: '', operationName: 'test operation name', - setup, + config: setup.config, + apmEventClient, serviceName: 'test service name', start: 1633456140000, end: 1633457078105, @@ -110,9 +114,11 @@ describe('fetchAndTransformGcMetrics', () => { }, }; const setup = { - apmEventClient: { search: () => Promise.resolve(response) }, config: { 'xpack.gc.metricsInterval': 0 }, } as unknown as Setup; + const apmEventClient = { + search: () => Promise.resolve(response), + } as unknown as APMEventClient; const fieldName = METRIC_JAVA_GC_COUNT; const { series } = await fetchAndTransformGcMetrics({ @@ -121,7 +127,8 @@ describe('fetchAndTransformGcMetrics', () => { fieldName, kuery: '', operationName: 'test operation name', - setup, + config: setup.config, + apmEventClient, serviceName: 'test service name', start: 1633456140000, end: 1633457078105, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index 08f0cf52d00c0..cb97295bbca01 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -10,7 +10,6 @@ import { euiLightVars as theme } from '@kbn/ui-theme'; import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { isFiniteNumber } from '../../../../../../common/utils/is_finite_number'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../../../../lib/helpers/metrics'; import { ChartBase } from '../../../types'; @@ -28,11 +27,14 @@ import { environmentQuery, serviceNodeNameQuery, } from '../../../../../../common/utils/environment_query'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; export async function fetchAndTransformGcMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, chartBase, @@ -43,7 +45,8 @@ export async function fetchAndTransformGcMetrics({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -52,8 +55,6 @@ export async function fetchAndTransformGcMetrics({ fieldName: typeof METRIC_JAVA_GC_COUNT | typeof METRIC_JAVA_GC_TIME; operationName: string; }) { - const { apmEventClient, config } = setup; - const { bucketSize } = getBucketSize({ start, end }); // GC rate and time are reported by the agents as monotonically diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts index 0476025594b26..6fac756ccef5f 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts @@ -8,9 +8,10 @@ import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics'; import { ChartBase } from '../../../types'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { [METRIC_JAVA_GC_COUNT]: { @@ -34,7 +35,8 @@ const chartBase: ChartBase = { function getGcRateChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -42,7 +44,8 @@ function getGcRateChart({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -51,7 +54,8 @@ function getGcRateChart({ return fetchAndTransformGcMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts index b1ef7b5e106f5..fed63945800da 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts @@ -8,9 +8,10 @@ import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics'; import { ChartBase } from '../../../types'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; +import { APMConfig } from '../../../../..'; const series = { [METRIC_JAVA_GC_TIME]: { @@ -34,7 +35,8 @@ const chartBase: ChartBase = { function getGcTimeChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -42,7 +44,8 @@ function getGcTimeChart({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -51,7 +54,8 @@ function getGcTimeChart({ return fetchAndTransformGcMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts index d57dfb184ca88..86c0b0af26054 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts @@ -13,10 +13,11 @@ import { METRIC_JAVA_HEAP_MEMORY_USED, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { ChartBase } from '../../../types'; import { JAVA_AGENT_NAMES } from '../../../../../../common/agent_name'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { heapMemoryUsed: { @@ -55,7 +56,8 @@ const chartBase: ChartBase = { export function getHeapMemoryChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -63,7 +65,8 @@ export function getHeapMemoryChart({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -72,7 +75,8 @@ export function getHeapMemoryChart({ return fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/index.ts index 5250884ed5e44..558e37af1cffc 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/index.ts @@ -7,18 +7,20 @@ import { withApmSpan } from '../../../../utils/with_apm_span'; import { getHeapMemoryChart } from './heap_memory'; -import { Setup } from '../../../../lib/helpers/setup_request'; import { getNonHeapMemoryChart } from './non_heap_memory'; import { getThreadCountChart } from './thread_count'; import { getCPUChartData } from '../shared/cpu'; import { getMemoryChartData } from '../shared/memory'; import { getGcRateChart } from './gc/get_gc_rate_chart'; import { getGcTimeChart } from './gc/get_gc_time_chart'; +import { APMConfig } from '../../../..'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export function getJavaMetricsCharts({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -26,7 +28,8 @@ export function getJavaMetricsCharts({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -36,7 +39,8 @@ export function getJavaMetricsCharts({ const options = { environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts index 379962d928e28..888af8d795afb 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts @@ -13,10 +13,11 @@ import { METRIC_JAVA_NON_HEAP_MEMORY_USED, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { JAVA_AGENT_NAMES } from '../../../../../../common/agent_name'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { nonHeapMemoryUsed: { @@ -52,7 +53,8 @@ const chartBase: ChartBase = { export async function getNonHeapMemoryChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -60,7 +62,8 @@ export async function getNonHeapMemoryChart({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -69,7 +72,8 @@ export async function getNonHeapMemoryChart({ return fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts index b9a49acb3d16e..74daa14438a15 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts @@ -11,10 +11,11 @@ import { METRIC_JAVA_THREAD_COUNT, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { JAVA_AGENT_NAMES } from '../../../../../../common/agent_name'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { threadCount: { @@ -44,7 +45,8 @@ const chartBase: ChartBase = { export async function getThreadCountChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -52,7 +54,8 @@ export async function getThreadCountChart({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -61,7 +64,8 @@ export async function getThreadCountChart({ return fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/active_instances.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/active_instances.ts deleted file mode 100644 index 02cbfc3b5704c..0000000000000 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/active_instances.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; -import { euiLightVars as theme } from '@kbn/ui-theme'; -import { - SERVICE_NAME, - SERVICE_NODE_NAME, -} from '../../../../../common/elasticsearch_fieldnames'; -import { environmentQuery } from '../../../../../common/utils/environment_query'; -import { getMetricsDateHistogramParams } from '../../../../lib/helpers/metrics'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { - getDocumentTypeFilterForTransactions, - getProcessorEventForTransactions, -} from '../../../../lib/helpers/transactions'; -import { GenericMetricsChart } from '../../fetch_and_transform_metrics'; - -export async function getActiveInstances({ - environment, - kuery, - setup, - serviceName, - start, - end, - searchAggregatedTransactions, -}: { - environment: string; - kuery: string; - setup: Setup; - serviceName: string; - start: number; - end: number; - searchAggregatedTransactions: boolean; -}): Promise { - const { apmEventClient, config } = setup; - - const aggs = { - activeInstances: { - cardinality: { - field: SERVICE_NODE_NAME, - }, - }, - }; - - const params = { - apm: { - events: [getProcessorEventForTransactions(searchAggregatedTransactions)], - }, - body: { - track_total_hits: false, - size: 0, - query: { - bool: { - filter: [ - { term: { [SERVICE_NAME]: serviceName } }, - ...rangeQuery(start, end), - ...environmentQuery(environment), - ...kqlQuery(kuery), - ...getDocumentTypeFilterForTransactions( - searchAggregatedTransactions - ), - ], - }, - }, - aggs: { - ...aggs, - timeseriesData: { - date_histogram: getMetricsDateHistogramParams({ - start, - end, - metricsInterval: config.metricsInterval, - }), - aggs, - }, - }, - }, - }; - - const { aggregations } = await apmEventClient.search( - 'get_active_instances', - params - ); - - return { - title: i18n.translate('xpack.apm.agentMetrics.serverless.activeInstances', { - defaultMessage: 'Active instances', - }), - key: 'active_instances', - yUnit: 'integer', - description: i18n.translate( - 'xpack.apm.agentMetrics.serverless.activeInstances.description', - { - defaultMessage: - 'This chart shows the number of active instances of your serverless function over time. Multiple active instances may be a result of provisioned concurrency for your function or an increase in concurrent load that scales your function on-demand. An increase in active instance can be an indicator for an increase in concurrent invocations.', - } - ), - series: [ - { - title: i18n.translate( - 'xpack.apm.agentMetrics.serverless.series.activeInstances', - { defaultMessage: 'Active instances' } - ), - key: 'active_instances', - type: 'bar', - color: theme.euiColorVis1, - overallValue: aggregations?.activeInstances.value ?? 0, - data: - aggregations?.timeseriesData.buckets.map((timeseriesBucket) => ({ - x: timeseriesBucket.key, - y: timeseriesBucket.activeInstances.value, - })) || [], - }, - ], - }; -} diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/index.ts deleted file mode 100644 index 5635dd5c0e50b..0000000000000 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/index.ts +++ /dev/null @@ -1,61 +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 { withApmSpan } from '../../../../utils/with_apm_span'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { getServerlessFunctionLatency } from './serverless_function_latency'; -import { getColdStartDuration } from './cold_start_duration'; -import { getMemoryChartData } from '../shared/memory'; -import { getComputeUsage } from './compute_usage'; -import { getActiveInstances } from './active_instances'; -import { getColdStartCount } from './cold_start_count'; -import { getSearchTransactionsEvents } from '../../../../lib/helpers/transactions'; - -export function getServerlessAgentMetricCharts({ - environment, - kuery, - setup, - serviceName, - start, - end, -}: { - environment: string; - kuery: string; - setup: Setup; - serviceName: string; - start: number; - end: number; -}) { - return withApmSpan('get_serverless_agent_metric_charts', async () => { - const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, - kuery, - start, - end, - }); - - const options = { - environment, - kuery, - setup, - serviceName, - start, - end, - }; - return await Promise.all([ - getServerlessFunctionLatency({ - ...options, - searchAggregatedTransactions, - }), - getMemoryChartData(options), - getColdStartDuration(options), - getColdStartCount(options), - getComputeUsage(options), - getActiveInstances({ ...options, searchAggregatedTransactions }), - ]); - }); -} diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts index d09b35e25e396..7da8e16bc28cc 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts @@ -11,9 +11,10 @@ import { METRIC_SYSTEM_CPU_PERCENT, METRIC_PROCESS_CPU_PERCENT, } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { systemCPUMax: { @@ -55,7 +56,8 @@ const chartBase: ChartBase = { export function getCPUChartData({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -63,7 +65,8 @@ export function getCPUChartData({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -72,7 +75,8 @@ export function getCPUChartData({ return fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/memory/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/memory/index.ts index a7e41ea71b725..c4aa4f82fe558 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/memory/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/memory/index.ts @@ -15,9 +15,10 @@ import { METRIC_SYSTEM_FREE_MEMORY, METRIC_SYSTEM_TOTAL_MEMORY, } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../../lib/helpers/setup_request'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { ChartBase } from '../../../types'; +import { APMConfig } from '../../../../..'; +import { APMEventClient } from '../../../../../lib/helpers/create_es_client/create_apm_event_client'; const series = { memoryUsedMax: { @@ -83,19 +84,21 @@ export const percentCgroupMemoryUsedScript = { export async function getMemoryChartData({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, - faasId, + serverlessId, start, end, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; - faasId?: string; + serverlessId?: string; start: number; end: number; }) { @@ -103,7 +106,8 @@ export async function getMemoryChartData({ const cgroupResponse = await fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -115,7 +119,7 @@ export async function getMemoryChartData({ }, additionalFilters: [ { exists: { field: METRIC_CGROUP_MEMORY_USAGE_BYTES } }, - ...termQuery(FAAS_ID, faasId), + ...termQuery(FAAS_ID, serverlessId), ], operationName: 'get_cgroup_memory_metrics_charts', }); @@ -124,7 +128,8 @@ export async function getMemoryChartData({ return await fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -137,7 +142,7 @@ export async function getMemoryChartData({ additionalFilters: [ { exists: { field: METRIC_SYSTEM_FREE_MEMORY } }, { exists: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, - ...termQuery(FAAS_ID, faasId), + ...termQuery(FAAS_ID, serverlessId), ], operationName: 'get_system_memory_metrics_charts', }); diff --git a/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts index 31ca4f54d932d..c23950b311e24 100644 --- a/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts @@ -12,9 +12,11 @@ import type { AggregationOptionsByType } from '@kbn/es-types'; import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getVizColorForIndex } from '../../../common/viz_colors'; -import { APMEventESSearchRequest } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import { + APMEventClient, + APMEventESSearchRequest, +} from '../../lib/helpers/create_es_client/create_apm_event_client'; import { getMetricsDateHistogramParams } from '../../lib/helpers/metrics'; -import { Setup } from '../../lib/helpers/setup_request'; import { ChartBase } from './types'; import { environmentQuery, @@ -22,6 +24,7 @@ import { } from '../../../common/utils/environment_query'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { ChartType, Coordinate, YUnit } from '../../../typings/timeseries'; +import { APMConfig } from '../..'; type MetricsAggregationMap = Unionize<{ min: AggregationOptionsByType['min']; @@ -63,7 +66,8 @@ export interface FetchAndTransformMetrics { export async function fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, start, @@ -75,7 +79,8 @@ export async function fetchAndTransformMetrics({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; start: number; @@ -85,8 +90,6 @@ export async function fetchAndTransformMetrics({ additionalFilters?: QueryDslQueryContainer[]; operationName: string; }): Promise { - const { apmEventClient, config } = setup; - const params: GenericMetricsRequest = { apm: { events: [ProcessorEvent.metric], diff --git a/x-pack/plugins/apm/server/routes/metrics/get_metrics_chart_data_by_agent.ts b/x-pack/plugins/apm/server/routes/metrics/get_metrics_chart_data_by_agent.ts index b5ae2bbe093ae..afe1e6e919a26 100644 --- a/x-pack/plugins/apm/server/routes/metrics/get_metrics_chart_data_by_agent.ts +++ b/x-pack/plugins/apm/server/routes/metrics/get_metrics_chart_data_by_agent.ts @@ -5,54 +5,50 @@ * 2.0. */ -import { Setup } from '../../lib/helpers/setup_request'; import { getJavaMetricsCharts } from './by_agent/java'; import { getDefaultMetricsCharts } from './by_agent/default'; -import { isJavaAgentName, isServerlessAgent } from '../../../common/agent_name'; +import { isJavaAgentName } from '../../../common/agent_name'; import { GenericMetricsChart } from './fetch_and_transform_metrics'; -import { getServerlessAgentMetricCharts } from './by_agent/serverless'; +import { APMConfig } from '../..'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getMetricsChartDataByAgent({ environment, kuery, - setup, + config, + apmEventClient, serviceName, serviceNodeName, agentName, start, end, - serviceRuntimeName, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; serviceNodeName?: string; agentName: string; start: number; end: number; - serviceRuntimeName?: string; }): Promise { const options = { environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, }; - const serverlessAgent = isServerlessAgent(serviceRuntimeName); - if (isJavaAgentName(agentName) && !serverlessAgent) { + if (isJavaAgentName(agentName)) { return getJavaMetricsCharts({ ...options, serviceNodeName, }); } - if (serverlessAgent) { - return getServerlessAgentMetricCharts(options); - } - return getDefaultMetricsCharts(options); } diff --git a/x-pack/plugins/apm/server/routes/metrics/get_service_nodes.ts b/x-pack/plugins/apm/server/routes/metrics/get_service_nodes.ts index e22ae93b25d53..2dd719717be00 100644 --- a/x-pack/plugins/apm/server/routes/metrics/get_service_nodes.ts +++ b/x-pack/plugins/apm/server/routes/metrics/get_service_nodes.ts @@ -21,25 +21,23 @@ import { SERVICE_NODE_NAME, } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; const getServiceNodes = async ({ kuery, - setup, + apmEventClient, serviceName, environment, start, end, }: { kuery: string; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; environment: string; start: number; end: number; }) => { - const { apmEventClient } = setup; - const params = { apm: { events: [ProcessorEvent.metric], diff --git a/x-pack/plugins/apm/server/routes/metrics/queries.test.ts b/x-pack/plugins/apm/server/routes/metrics/queries.test.ts index af36a030157c0..ea14dc2082921 100644 --- a/x-pack/plugins/apm/server/routes/metrics/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/metrics/queries.test.ts @@ -22,9 +22,10 @@ describe('metrics queries', () => { const createTests = (serviceNodeName?: string) => { it('fetches cpu chart data', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getCPUChartData({ - setup, + config: setup.config, + apmEventClient, serviceName: 'foo', serviceNodeName, environment: ENVIRONMENT_ALL.value, @@ -38,9 +39,10 @@ describe('metrics queries', () => { }); it('fetches memory chart data', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getMemoryChartData({ - setup, + config: setup.config, + apmEventClient, serviceName: 'foo', serviceNodeName, environment: ENVIRONMENT_ALL.value, @@ -54,9 +56,10 @@ describe('metrics queries', () => { }); it('fetches heap memory chart data', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getHeapMemoryChart({ - setup, + config: setup.config, + apmEventClient, serviceName: 'foo', serviceNodeName, environment: ENVIRONMENT_ALL.value, @@ -70,9 +73,10 @@ describe('metrics queries', () => { }); it('fetches non heap memory chart data', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getNonHeapMemoryChart({ - setup, + config: setup.config, + apmEventClient, serviceName: 'foo', serviceNodeName, environment: ENVIRONMENT_ALL.value, @@ -86,9 +90,10 @@ describe('metrics queries', () => { }); it('fetches thread count chart data', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getThreadCountChart({ - setup, + config: setup.config, + apmEventClient, serviceName: 'foo', serviceNodeName, environment: ENVIRONMENT_ALL.value, diff --git a/x-pack/plugins/apm/server/routes/metrics/route.ts b/x-pack/plugins/apm/server/routes/metrics/route.ts index 8aea9cc5a981c..8fd878222fc52 100644 --- a/x-pack/plugins/apm/server/routes/metrics/route.ts +++ b/x-pack/plugins/apm/server/routes/metrics/route.ts @@ -6,12 +6,14 @@ */ import * as t from 'io-ts'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; import { FetchAndTransformMetrics } from './fetch_and_transform_metrics'; import { getMetricsChartDataByAgent } from './get_metrics_chart_data_by_agent'; import { getServiceNodes } from './get_service_nodes'; +import { metricsServerlessRouteRepository } from './serverless/route'; const metricsChartsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/services/{serviceName}/metrics/charts', @@ -25,7 +27,6 @@ const metricsChartsRoute = createApmServerRoute({ }), t.partial({ serviceNodeName: t.string, - serviceRuntimeName: t.string, }), environmentRt, kueryRt, @@ -39,28 +40,24 @@ const metricsChartsRoute = createApmServerRoute({ charts: FetchAndTransformMetrics[]; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { serviceName } = params.path; - const { - agentName, - environment, - kuery, - serviceNodeName, - start, - end, - serviceRuntimeName, - } = params.query; + const { agentName, environment, kuery, serviceNodeName, start, end } = + params.query; const charts = await getMetricsChartDataByAgent({ environment, kuery, - setup, + config: setup.config, + apmEventClient, serviceName, agentName, serviceNodeName, start, end, - serviceRuntimeName, }); return { charts }; @@ -88,14 +85,14 @@ const serviceMetricsJvm = createApmServerRoute({ threadCount: number | null; }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { kuery, environment, start, end } = params.query; const serviceNodes = await getServiceNodes({ kuery, - setup, + apmEventClient, serviceName, environment, start, @@ -108,4 +105,5 @@ const serviceMetricsJvm = createApmServerRoute({ export const metricsRouteRepository = { ...metricsChartsRoute, ...serviceMetricsJvm, + ...metricsServerlessRouteRepository, }; diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_overview.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_overview.ts new file mode 100644 index 0000000000000..5361070e50c8d --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_overview.ts @@ -0,0 +1,191 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { + FAAS_BILLED_DURATION, + FAAS_DURATION, + FAAS_ID, + METRICSET_NAME, + METRIC_SYSTEM_FREE_MEMORY, + METRIC_SYSTEM_TOTAL_MEMORY, + SERVICE_NAME, + SERVICE_NODE_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { getServerlessFunctionNameFromId } from '../../../../common/serverless'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { Coordinate } from '../../../../typings/timeseries'; +import { getBucketSize } from '../../../lib/helpers/get_bucket_size'; +import { calcMemoryUsed } from './helper'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +interface ActiveInstanceTimeseries { + serverlessDuration: Coordinate[]; + billedDuration: Coordinate[]; +} + +export interface ActiveInstanceOverview { + activeInstanceName: string; + serverlessId: string; + serverlessFunctionName: string; + timeseries: ActiveInstanceTimeseries; + serverlessDurationAvg: number | null; + billedDurationAvg: number | null; + avgMemoryUsed?: number | null; + memorySize: number | null; +} + +export async function getServerlessActiveInstancesOverview({ + end, + environment, + kuery, + serviceName, + start, + serverlessId, + apmEventClient, +}: { + environment: string; + kuery: string; + serviceName: string; + start: number; + end: number; + serverlessId?: string; + apmEventClient: APMEventClient; +}) { + const { intervalString } = getBucketSize({ + start, + end, + numBuckets: 20, + }); + + const aggs = { + faasDurationAvg: { avg: { field: FAAS_DURATION } }, + faasBilledDurationAvg: { avg: { field: FAAS_BILLED_DURATION } }, + }; + + const params = { + apm: { + events: [ProcessorEvent.metric], + }, + body: { + track_total_hits: 1, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(METRICSET_NAME, 'app'), + { term: { [SERVICE_NAME]: serviceName } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...termQuery(FAAS_ID, serverlessId), + ], + }, + }, + aggs: { + activeInstances: { + terms: { field: SERVICE_NODE_NAME }, + aggs: { + serverlessFunctions: { + terms: { field: FAAS_ID }, + aggs: { + ...{ + ...aggs, + maxTotalMemory: { + max: { field: METRIC_SYSTEM_TOTAL_MEMORY }, + }, + avgTotalMemory: { + avg: { field: METRIC_SYSTEM_TOTAL_MEMORY }, + }, + avgFreeMemory: { avg: { field: METRIC_SYSTEM_FREE_MEMORY } }, + }, + timeseries: { + date_histogram: { + field: '@timestamp', + fixed_interval: intervalString, + min_doc_count: 0, + extended_bounds: { + min: start, + max: end, + }, + }, + aggs, + }, + }, + }, + }, + }, + }, + }, + }; + + const response = await apmEventClient.search( + 'ger_serverless_active_instances_overview', + params + ); + + return ( + response.aggregations?.activeInstances?.buckets?.flatMap((bucket) => { + const activeInstanceName = bucket.key as string; + const serverlessFunctionsDetails = + bucket.serverlessFunctions.buckets.reduce( + (acc, curr) => { + const currentServerlessId = curr.key as string; + + const timeseries = + curr.timeseries.buckets.reduce( + (timeseriesAcc, timeseriesCurr) => { + return { + serverlessDuration: [ + ...timeseriesAcc.serverlessDuration, + { + x: timeseriesCurr.key, + y: timeseriesCurr.faasDurationAvg.value, + }, + ], + billedDuration: [ + ...timeseriesAcc.billedDuration, + { + x: timeseriesCurr.key, + y: timeseriesCurr.faasBilledDurationAvg.value, + }, + ], + }; + }, + { + serverlessDuration: [], + billedDuration: [], + } + ); + return [ + ...acc, + { + activeInstanceName, + serverlessId: currentServerlessId, + serverlessFunctionName: + getServerlessFunctionNameFromId(currentServerlessId), + timeseries, + serverlessDurationAvg: curr.faasDurationAvg.value, + billedDurationAvg: curr.faasBilledDurationAvg.value, + avgMemoryUsed: calcMemoryUsed({ + memoryFree: curr.avgFreeMemory.value, + memoryTotal: curr.avgTotalMemory.value, + }), + memorySize: curr.avgTotalMemory.value, + }, + ]; + }, + [] + ); + return serverlessFunctionsDetails; + }) || [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_timeseries.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_timeseries.ts new file mode 100644 index 0000000000000..facd270aec728 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_active_instances_timeseries.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + FAAS_ID, + METRICSET_NAME, + SERVICE_NAME, + SERVICE_NODE_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { Coordinate } from '../../../../typings/timeseries'; +import { getMetricsDateHistogramParams } from '../../../lib/helpers/metrics'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { APMConfig } from '../../..'; + +export async function getActiveInstancesTimeseries({ + environment, + kuery, + serviceName, + start, + end, + serverlessId, + config, + apmEventClient, +}: { + environment: string; + kuery: string; + serviceName: string; + start: number; + end: number; + serverlessId?: string; + config: APMConfig; + apmEventClient: APMEventClient; +}): Promise { + const aggs = { + activeInstances: { + cardinality: { + field: SERVICE_NODE_NAME, + }, + }, + }; + + const params = { + apm: { + events: [ProcessorEvent.metric], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(METRICSET_NAME, 'app'), + { term: { [SERVICE_NAME]: serviceName } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...termQuery(FAAS_ID, serverlessId), + ], + }, + }, + aggs: { + ...aggs, + timeseriesData: { + date_histogram: getMetricsDateHistogramParams({ + start, + end, + metricsInterval: config.metricsInterval, + }), + aggs, + }, + }, + }, + }; + + const { aggregations } = await apmEventClient.search( + 'get_active_instances', + params + ); + + return ( + aggregations?.timeseriesData?.buckets?.map((timeseriesBucket) => ({ + x: timeseriesBucket.key, + y: timeseriesBucket.activeInstances.value, + })) || [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_count.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_count_chart.ts similarity index 66% rename from x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_count.ts rename to x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_count_chart.ts index d884aa8dce446..a56e6c4c8764c 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_count.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_count_chart.ts @@ -8,17 +8,19 @@ import { i18n } from '@kbn/i18n'; import { termQuery } from '@kbn/observability-plugin/server'; import { euiLightVars as theme } from '@kbn/ui-theme'; +import { APMConfig } from '../../..'; import { FAAS_COLDSTART, + FAAS_ID, METRICSET_NAME, -} from '../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { fetchAndTransformMetrics } from '../../fetch_and_transform_metrics'; -import { ChartBase } from '../../types'; +} from '../../../../common/elasticsearch_fieldnames'; +import { fetchAndTransformMetrics } from '../fetch_and_transform_metrics'; +import { ChartBase } from '../types'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; const chartBase: ChartBase = { - title: i18n.translate('xpack.apm.agentMetrics.serverless.coldStart', { - defaultMessage: 'Cold start', + title: i18n.translate('xpack.apm.agentMetrics.serverless.coldStart.title', { + defaultMessage: 'Cold starts', }), key: 'cold_start_count', type: 'bar', @@ -33,25 +35,30 @@ const chartBase: ChartBase = { }, }; -export function getColdStartCount({ +export function getColdStartCountChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, + serverlessId, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; + serverlessId?: string; }) { return fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, @@ -59,7 +66,8 @@ export function getColdStartCount({ aggs: { coldStart: { sum: { field: FAAS_COLDSTART } } }, additionalFilters: [ ...termQuery(FAAS_COLDSTART, true), - ...termQuery(METRICSET_NAME, 'transaction'), + ...termQuery(FAAS_ID, serverlessId), + ...termQuery(METRICSET_NAME, 'app'), ], operationName: 'get_cold_start_count', }); diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_duration_chart.ts similarity index 60% rename from x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts rename to x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_duration_chart.ts index 5a78f5d97d5e8..b1802edb5440b 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_cold_start_duration_chart.ts @@ -7,11 +7,17 @@ import { i18n } from '@kbn/i18n'; import { euiLightVars as theme } from '@kbn/ui-theme'; -import { FAAS_COLDSTART_DURATION } from '../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { fetchAndTransformMetrics } from '../../fetch_and_transform_metrics'; -import { ChartBase } from '../../types'; -import { isFiniteNumber } from '../../../../../common/utils/is_finite_number'; +import { termQuery } from '@kbn/observability-plugin/server'; +import { + FAAS_COLDSTART_DURATION, + FAAS_ID, + METRICSET_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { fetchAndTransformMetrics } from '../fetch_and_transform_metrics'; +import { ChartBase } from '../types'; +import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; +import { APMConfig } from '../../..'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; const chartBase: ChartBase = { title: i18n.translate('xpack.apm.agentMetrics.serverless.coldStartDuration', { @@ -38,37 +44,46 @@ const chartBase: ChartBase = { ), }; -export async function getColdStartDuration({ +export async function getColdStartDurationChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, + serverlessId, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; + serverlessId?: string; }) { const coldStartDurationMetric = await fetchAndTransformMetrics({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, chartBase, aggs: { coldStart: { avg: { field: FAAS_COLDSTART_DURATION } } }, - additionalFilters: [{ exists: { field: FAAS_COLDSTART_DURATION } }], + additionalFilters: [ + { exists: { field: FAAS_COLDSTART_DURATION } }, + ...termQuery(FAAS_ID, serverlessId), + ...termQuery(METRICSET_NAME, 'app'), + ], operationName: 'get_cold_start_duration', }); const [series] = coldStartDurationMetric.series; - const data = series.data.map(({ x, y }) => ({ + const data = series?.data?.map(({ x, y }) => ({ x, // Cold start duration duration is stored in ms, convert it to microseconds so it uses the same unit as the other charts y: isFiniteNumber(y) ? y * 1000 : y, @@ -76,13 +91,15 @@ export async function getColdStartDuration({ return { ...coldStartDurationMetric, - series: [ - { - ...series, - // Cold start duration duration is stored in ms, convert it to microseconds - overallValue: series.overallValue * 1000, - data, - }, - ], + series: series + ? [ + { + ...series, + // Cold start duration duration is stored in ms, convert it to microseconds + overallValue: series.overallValue * 1000, + data, + }, + ] + : [], }; } diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/compute_usage.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_compute_usage_chart.ts similarity index 85% rename from x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/compute_usage.ts rename to x-pack/plugins/apm/server/routes/metrics/serverless/get_compute_usage_chart.ts index bb8d5023c9af2..201961113cac0 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/compute_usage.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_compute_usage_chart.ts @@ -13,17 +13,19 @@ import { termQuery, } from '@kbn/observability-plugin/server'; import { euiLightVars as theme } from '@kbn/ui-theme'; +import { APMConfig } from '../../..'; import { FAAS_BILLED_DURATION, + FAAS_ID, METRICSET_NAME, METRIC_SYSTEM_TOTAL_MEMORY, SERVICE_NAME, -} from '../../../../../common/elasticsearch_fieldnames'; -import { environmentQuery } from '../../../../../common/utils/environment_query'; -import { isFiniteNumber } from '../../../../../common/utils/is_finite_number'; -import { getMetricsDateHistogramParams } from '../../../../lib/helpers/metrics'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { GenericMetricsChart } from '../../fetch_and_transform_metrics'; +} from '../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; +import { getMetricsDateHistogramParams } from '../../../lib/helpers/metrics'; +import { GenericMetricsChart } from '../fetch_and_transform_metrics'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; /** * To calculate the compute usage we need to multiply the "system.memory.total" by "faas.billed_duration". @@ -47,23 +49,25 @@ function calculateComputeUsageGBSeconds({ return totalMemoryGB * faasBilledDurationSec; } -export async function getComputeUsage({ +export async function getComputeUsageChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, + serverlessId, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; + serverlessId?: string; }): Promise { - const { apmEventClient, config } = setup; - const aggs = { avgFaasBilledDuration: { avg: { field: FAAS_BILLED_DURATION } }, avgTotalMemory: { avg: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, @@ -85,6 +89,7 @@ export async function getComputeUsage({ ...kqlQuery(kuery), { exists: { field: FAAS_BILLED_DURATION } }, ...termQuery(METRICSET_NAME, 'app'), + ...termQuery(FAAS_ID, serverlessId), ], }, }, diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_agent_metrics_chart.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_agent_metrics_chart.ts new file mode 100644 index 0000000000000..1d1bf19b635be --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_agent_metrics_chart.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSearchTransactionsEvents } from '../../../lib/helpers/transactions'; +import { withApmSpan } from '../../../utils/with_apm_span'; +import { getMemoryChartData } from '../by_agent/shared/memory'; +import { getColdStartCountChart } from './get_cold_start_count_chart'; +import { getColdStartDurationChart } from './get_cold_start_duration_chart'; +import { getComputeUsageChart } from './get_compute_usage_chart'; +import { getServerlessFunctionLatencyChart } from './get_serverless_function_latency_chart'; +import { APMConfig } from '../../..'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +export function getServerlessAgentMetricsCharts({ + environment, + kuery, + config, + apmEventClient, + serviceName, + start, + end, + serverlessId, +}: { + environment: string; + kuery: string; + config: APMConfig; + apmEventClient: APMEventClient; + serviceName: string; + start: number; + end: number; + serverlessId?: string; +}) { + return withApmSpan('get_serverless_agent_metric_charts', async () => { + const searchAggregatedTransactions = await getSearchTransactionsEvents({ + config, + apmEventClient, + kuery, + start, + end, + }); + + const options = { + environment, + kuery, + apmEventClient, + config, + serviceName, + start, + end, + serverlessId, + }; + return await Promise.all([ + getServerlessFunctionLatencyChart({ + ...options, + searchAggregatedTransactions, + }), + getMemoryChartData(options), + getColdStartDurationChart(options), + getColdStartCountChart(options), + getComputeUsageChart(options), + ]); + }); +} diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_function_latency_chart.ts similarity index 57% rename from x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts rename to x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_function_latency_chart.ts index 0a27c66ef036b..47593c3f48409 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_function_latency_chart.ts @@ -7,17 +7,24 @@ import { i18n } from '@kbn/i18n'; import { euiLightVars as theme } from '@kbn/ui-theme'; -import { FAAS_BILLED_DURATION } from '../../../../../common/elasticsearch_fieldnames'; -import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types'; -import { isFiniteNumber } from '../../../../../common/utils/is_finite_number'; -import { getVizColorForIndex } from '../../../../../common/viz_colors'; -import { Setup } from '../../../../lib/helpers/setup_request'; -import { getLatencyTimeseries } from '../../../transactions/get_latency_charts'; +import { termQuery } from '@kbn/observability-plugin/server'; +import { isEmpty } from 'lodash'; +import { + FAAS_BILLED_DURATION, + FAAS_ID, + METRICSET_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; +import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; +import { getVizColorForIndex } from '../../../../common/viz_colors'; +import { getLatencyTimeseries } from '../../transactions/get_latency_charts'; +import { APMConfig } from '../../..'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { fetchAndTransformMetrics, GenericMetricsChart, -} from '../../fetch_and_transform_metrics'; -import { ChartBase } from '../../types'; +} from '../fetch_and_transform_metrics'; +import { ChartBase } from '../types'; const billedDurationAvg = { title: i18n.translate('xpack.apm.agentMetrics.serverless.billedDurationAvg', { @@ -27,7 +34,7 @@ const billedDurationAvg = { const chartBase: ChartBase = { title: i18n.translate('xpack.apm.agentMetrics.serverless.avgDuration', { - defaultMessage: 'Avg. Duration', + defaultMessage: 'Lambda Duration', }), key: 'avg_duration', type: 'linemark', @@ -45,29 +52,32 @@ const chartBase: ChartBase = { async function getServerlessLantecySeries({ environment, kuery, - setup, + apmEventClient, serviceName, start, end, + serverlessId, searchAggregatedTransactions, }: { environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; + serverlessId?: string; searchAggregatedTransactions: boolean; }): Promise { const transactionLatency = await getLatencyTimeseries({ environment, kuery, serviceName, - setup, + apmEventClient, searchAggregatedTransactions, latencyAggregationType: LatencyAggregationType.avg, start, end, + serverlessId, }); return [ @@ -85,27 +95,32 @@ async function getServerlessLantecySeries({ ]; } -export async function getServerlessFunctionLatency({ +export async function getServerlessFunctionLatencyChart({ environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, + serverlessId, searchAggregatedTransactions, }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; + serverlessId?: string; searchAggregatedTransactions: boolean; }): Promise { const options = { environment, kuery, - setup, + config, + apmEventClient, serviceName, start, end, @@ -118,29 +133,43 @@ export async function getServerlessFunctionLatency({ aggs: { billedDurationAvg: { avg: { field: FAAS_BILLED_DURATION } }, }, - additionalFilters: [{ exists: { field: FAAS_BILLED_DURATION } }], + additionalFilters: [ + { exists: { field: FAAS_BILLED_DURATION } }, + ...termQuery(FAAS_ID, serverlessId), + ...termQuery(METRICSET_NAME, 'app'), + ], operationName: 'get_billed_duration', }), - getServerlessLantecySeries({ ...options, searchAggregatedTransactions }), + getServerlessLantecySeries({ + ...options, + serverlessId, + searchAggregatedTransactions, + }), ]); - const [series] = billedDurationMetrics.series; - const data = series.data.map(({ x, y }) => ({ - x, - // Billed duration is stored in ms, convert it to microseconds so it uses the same unit as the other chart - y: isFiniteNumber(y) ? y * 1000 : y, - })); + const series = []; + + const [billedDurationSeries] = billedDurationMetrics.series; + if (billedDurationSeries) { + const data = billedDurationSeries.data?.map(({ x, y }) => ({ + x, + // Billed duration is stored in ms, convert it to microseconds so it uses the same unit as the other chart + y: isFiniteNumber(y) ? y * 1000 : y, + })); + series.push({ + ...billedDurationSeries, + // Billed duration is stored in ms, convert it to microseconds + overallValue: billedDurationSeries.overallValue * 1000, + data: data || [], + }); + } + + if (!isEmpty(serverlessDurationSeries[0].data)) { + series.push(...serverlessDurationSeries); + } return { ...billedDurationMetrics, - series: [ - { - ...series, - // Billed duration is stored in ms, convert it to microseconds - overallValue: series.overallValue * 1000, - data, - }, - ...serverlessDurationSeries, - ], + series, }; } diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_functions_overview.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_functions_overview.ts new file mode 100644 index 0000000000000..236e950c1f13c --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_functions_overview.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { + FAAS_BILLED_DURATION, + FAAS_COLDSTART, + FAAS_DURATION, + FAAS_ID, + METRICSET_NAME, + METRIC_SYSTEM_FREE_MEMORY, + METRIC_SYSTEM_TOTAL_MEMORY, + SERVICE_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { getServerlessFunctionNameFromId } from '../../../../common/serverless'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { calcMemoryUsed } from './helper'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +export async function getServerlessFunctionsOverview({ + end, + environment, + kuery, + serviceName, + start, + apmEventClient, +}: { + environment: string; + kuery: string; + serviceName: string; + start: number; + end: number; + apmEventClient: APMEventClient; +}) { + const params = { + apm: { + events: [ProcessorEvent.metric], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(METRICSET_NAME, 'app'), + { term: { [SERVICE_NAME]: serviceName } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ], + }, + }, + aggs: { + serverlessFunctions: { + terms: { field: FAAS_ID }, + aggs: { + faasDurationAvg: { avg: { field: FAAS_DURATION } }, + faasBilledDurationAvg: { avg: { field: FAAS_BILLED_DURATION } }, + coldStartCount: { sum: { field: FAAS_COLDSTART } }, + maxTotalMemory: { max: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, + avgTotalMemory: { avg: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, + avgFreeMemory: { avg: { field: METRIC_SYSTEM_FREE_MEMORY } }, + }, + }, + }, + }, + }; + + const response = await apmEventClient.search( + 'ger_serverless_functions_overview', + params + ); + + const serverlessFunctionsOverview = + response.aggregations?.serverlessFunctions?.buckets?.map((bucket) => { + const serverlessId = bucket.key as string; + return { + serverlessId, + serverlessFunctionName: getServerlessFunctionNameFromId(serverlessId), + serverlessDurationAvg: bucket.faasDurationAvg.value, + billedDurationAvg: bucket.faasBilledDurationAvg.value, + coldStartCount: bucket.coldStartCount.value, + avgMemoryUsed: calcMemoryUsed({ + memoryFree: bucket.avgFreeMemory.value, + memoryTotal: bucket.avgTotalMemory.value, + }), + memorySize: bucket.maxTotalMemory.value, + }; + }); + + return serverlessFunctionsOverview || []; +} diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts new file mode 100644 index 0000000000000..d3f292a11b872 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + termQuery, + kqlQuery, + rangeQuery, +} from '@kbn/observability-plugin/server'; +import { + FAAS_BILLED_DURATION, + FAAS_DURATION, + FAAS_ID, + METRICSET_NAME, + METRIC_SYSTEM_FREE_MEMORY, + METRIC_SYSTEM_TOTAL_MEMORY, + SERVICE_NAME, +} from '../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { calcMemoryUsedRate } from './helper'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +export async function getServerlessSummary({ + end, + environment, + kuery, + serviceName, + start, + serverlessId, + apmEventClient, +}: { + environment: string; + kuery: string; + serviceName: string; + start: number; + end: number; + serverlessId?: string; + apmEventClient: APMEventClient; +}) { + const params = { + apm: { + events: [ProcessorEvent.metric], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(METRICSET_NAME, 'app'), + { term: { [SERVICE_NAME]: serviceName } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...termQuery(FAAS_ID, serverlessId), + ], + }, + }, + aggs: { + totalFunctions: { cardinality: { field: FAAS_ID } }, + faasDurationAvg: { avg: { field: FAAS_DURATION } }, + faasBilledDurationAvg: { avg: { field: FAAS_BILLED_DURATION } }, + avgTotalMemory: { avg: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, + avgFreeMemory: { avg: { field: METRIC_SYSTEM_FREE_MEMORY } }, + }, + }, + }; + + const response = await apmEventClient.search( + 'ger_serverless_summary', + params + ); + + return { + memoryUsageAvgRate: calcMemoryUsedRate({ + memoryFree: response.aggregations?.avgFreeMemory?.value, + memoryTotal: response.aggregations?.avgTotalMemory?.value, + }), + serverlessFunctionsTotal: response.aggregations?.totalFunctions?.value, + serverlessDurationAvg: response.aggregations?.faasDurationAvg?.value, + billedDurationAvg: response.aggregations?.faasBilledDurationAvg?.value, + }; +} diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts new file mode 100644 index 0000000000000..c6927f36a8eb9 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { calcMemoryUsed, calcMemoryUsedRate } from './helper'; +describe('calcMemoryUsed', () => { + it('returns undefined when memory values are no a number', () => { + [ + { memoryFree: null, memoryTotal: null }, + { memoryFree: undefined, memoryTotal: undefined }, + { memoryFree: 100, memoryTotal: undefined }, + { memoryFree: undefined, memoryTotal: 100 }, + ].forEach(({ memoryFree, memoryTotal }) => { + expect(calcMemoryUsed({ memoryFree, memoryTotal })).toBeUndefined(); + }); + }); + + it('returns correct memory used', () => { + expect(calcMemoryUsed({ memoryFree: 50, memoryTotal: 100 })).toBe(50); + }); +}); + +describe('calcMemoryUsedRate', () => { + it('returns undefined when memory values are no a number', () => { + [ + { memoryFree: null, memoryTotal: null }, + { memoryFree: undefined, memoryTotal: undefined }, + { memoryFree: 100, memoryTotal: undefined }, + { memoryFree: undefined, memoryTotal: 100 }, + ].forEach(({ memoryFree, memoryTotal }) => { + expect(calcMemoryUsedRate({ memoryFree, memoryTotal })).toBeUndefined(); + }); + }); + + it('returns correct memory used rate', () => { + expect(calcMemoryUsedRate({ memoryFree: 50, memoryTotal: 100 })).toBe(0.5); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts new file mode 100644 index 0000000000000..0c16ee101c735 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; + +export function calcMemoryUsedRate({ + memoryFree, + memoryTotal, +}: { + memoryFree?: number | null; + memoryTotal?: number | null; +}) { + if (!isFiniteNumber(memoryFree) || !isFiniteNumber(memoryTotal)) { + return undefined; + } + + return (memoryTotal - memoryFree) / memoryTotal; +} + +export function calcMemoryUsed({ + memoryFree, + memoryTotal, +}: { + memoryFree?: number | null; + memoryTotal?: number | null; +}) { + if (!isFiniteNumber(memoryFree) || !isFiniteNumber(memoryTotal)) { + return undefined; + } + + return memoryTotal - memoryFree; +} diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts new file mode 100644 index 0000000000000..af2a0aa0834f7 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts @@ -0,0 +1,189 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { setupRequest } from '../../../lib/helpers/setup_request'; +import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; +import { environmentRt, kueryRt, rangeRt } from '../../default_api_types'; +import { getServerlessAgentMetricsCharts } from './get_serverless_agent_metrics_chart'; +import { getServerlessActiveInstancesOverview } from './get_active_instances_overview'; +import { getServerlessFunctionsOverview } from './get_serverless_functions_overview'; +import { getServerlessSummary } from './get_serverless_summary'; +import { getActiveInstancesTimeseries } from './get_active_instances_timeseries'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; + +const serverlessMetricsChartsRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/services/{serviceName}/metrics/serverless/charts', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + environmentRt, + kueryRt, + rangeRt, + t.partial({ serverlessId: t.string }), + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ + charts: Awaited>; + }> => { + const { params } = resources; + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); + + const { serviceName } = params.path; + const { environment, kuery, start, end, serverlessId } = params.query; + + const charts = await getServerlessAgentMetricsCharts({ + environment, + start, + end, + kuery, + config: setup.config, + apmEventClient, + serviceName, + serverlessId, + }); + return { charts }; + }, +}); + +const serverlessMetricsActiveInstancesRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + environmentRt, + kueryRt, + rangeRt, + t.partial({ serverlessId: t.string }), + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ + activeInstances: Awaited< + ReturnType + >; + timeseries: Awaited>; + }> => { + const { params } = resources; + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); + + const { serviceName } = params.path; + const { environment, kuery, start, end, serverlessId } = params.query; + + const options = { + environment, + start, + end, + kuery, + setup, + serviceName, + serverlessId, + apmEventClient, + }; + + const [activeInstances, timeseries] = await Promise.all([ + getServerlessActiveInstancesOverview(options), + getActiveInstancesTimeseries({ ...options, config: setup.config }), + ]); + return { activeInstances, timeseries }; + }, +}); + +const serverlessMetricsFunctionsOverviewRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([environmentRt, kueryRt, rangeRt]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ + serverlessFunctionsOverview: Awaited< + ReturnType + >; + }> => { + const { params } = resources; + const apmEventClient = await getApmEventClient(resources); + + const { serviceName } = params.path; + const { environment, kuery, start, end } = params.query; + + const serverlessFunctionsOverview = await getServerlessFunctionsOverview({ + environment, + start, + end, + kuery, + apmEventClient, + serviceName, + }); + return { serverlessFunctionsOverview }; + }, +}); + +const serverlessMetricsSummaryRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/services/{serviceName}/metrics/serverless/summary', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + environmentRt, + kueryRt, + rangeRt, + t.partial({ serverlessId: t.string }), + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise>> => { + const { params } = resources; + const apmEventClient = await getApmEventClient(resources); + + const { serviceName } = params.path; + const { environment, kuery, start, end, serverlessId } = params.query; + + return getServerlessSummary({ + environment, + start, + end, + kuery, + apmEventClient, + serviceName, + serverlessId, + }); + }, +}); + +export const metricsServerlessRouteRepository = { + ...serverlessMetricsChartsRoute, + ...serverlessMetricsSummaryRoute, + ...serverlessMetricsFunctionsOverviewRoute, + ...serverlessMetricsActiveInstancesRoute, +}; diff --git a/x-pack/plugins/apm/server/routes/observability_overview/get_service_count.ts b/x-pack/plugins/apm/server/routes/observability_overview/get_service_count.ts index ecdf1c792ffe5..315f9345bff84 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview/get_service_count.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview/get_service_count.ts @@ -8,22 +8,20 @@ import { rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceCount({ - setup, + apmEventClient, searchAggregatedTransactions, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { apm: { events: [ diff --git a/x-pack/plugins/apm/server/routes/observability_overview/get_transactions_per_minute.ts b/x-pack/plugins/apm/server/routes/observability_overview/get_transactions_per_minute.ts index cfc89a7589cdf..8f99b6a08ae84 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview/get_transactions_per_minute.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview/get_transactions_per_minute.ts @@ -11,30 +11,28 @@ import { TRANSACTION_REQUEST, } from '../../../common/transaction_types'; import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../lib/helpers/transactions'; import { calculateThroughputWithRange } from '../../lib/helpers/calculate_throughput'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransactionsPerMinute({ - setup, + apmEventClient, bucketSize, searchAggregatedTransactions, start, end, intervalString, }: { - setup: Setup; + apmEventClient: APMEventClient; bucketSize: number; intervalString: string; searchAggregatedTransactions: boolean; start: number; end: number; }) { - const { apmEventClient } = setup; - const { aggregations } = await apmEventClient.search( 'observability_overview_get_transactions_per_minute', { diff --git a/x-pack/plugins/apm/server/routes/observability_overview/has_data.ts b/x-pack/plugins/apm/server/routes/observability_overview/has_data.ts index 384f26b31e70c..66436caa7a405 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview/has_data.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview/has_data.ts @@ -6,10 +6,16 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import { ApmIndicesConfig } from '../settings/apm_indices/get_apm_indices'; -export async function getHasData({ setup }: { setup: Setup }) { - const { apmEventClient } = setup; +export async function getHasData({ + indices, + apmEventClient, +}: { + indices: ApmIndicesConfig; + apmEventClient: APMEventClient; +}) { try { const params = { apm: { @@ -32,12 +38,12 @@ export async function getHasData({ setup }: { setup: Setup }) { ); return { hasData: response.hits.total.value > 0, - indices: setup.indices, + indices, }; } catch (e) { return { hasData: false, - indices: setup.indices, + indices, }; } } diff --git a/x-pack/plugins/apm/server/routes/observability_overview/route.ts b/x-pack/plugins/apm/server/routes/observability_overview/route.ts index 4ed5332801ef3..7128d664b0cef 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview/route.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview/route.ts @@ -15,6 +15,7 @@ import { rangeRt } from '../default_api_types'; import { getSearchTransactionsEvents } from '../../lib/helpers/transactions'; import { withApmSpan } from '../../utils/with_apm_span'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const observabilityOverviewHasDataRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/observability_overview/has_data', @@ -25,8 +26,11 @@ const observabilityOverviewHasDataRoute = createApmServerRoute({ hasData: boolean; indices: import('./../../../../observability/common/typings').ApmIndicesConfig; }> => { - const setup = await setupRequest(resources); - return await getHasData({ setup }); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); + return await getHasData({ indices: setup.indices, apmEventClient }); }, }); @@ -47,11 +51,14 @@ const observabilityOverviewRoute = createApmServerRoute({ | { value: undefined; timeseries: never[] } | { value: number; timeseries: Array<{ x: number; y: number | null }> }; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { bucketSize, intervalString, start, end } = resources.params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -71,13 +78,13 @@ const observabilityOverviewRoute = createApmServerRoute({ }> => { const [serviceCount, transactionPerMinute] = await Promise.all([ getServiceCount({ - setup, + apmEventClient, searchAggregatedTransactions, start, end, }), getTransactionsPerMinute({ - setup, + apmEventClient, bucketSize, searchAggregatedTransactions, start, diff --git a/x-pack/plugins/apm/server/routes/service_groups/get_services_counts.ts b/x-pack/plugins/apm/server/routes/service_groups/get_services_counts.ts index c820cdd8445fc..b261c2a4cfd4a 100644 --- a/x-pack/plugins/apm/server/routes/service_groups/get_services_counts.ts +++ b/x-pack/plugins/apm/server/routes/service_groups/get_services_counts.ts @@ -8,23 +8,21 @@ import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { rangeQuery, kqlQuery } from '@kbn/observability-plugin/server'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { Setup } from '../../lib/helpers/setup_request'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { SavedServiceGroup } from '../../../common/service_groups'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServicesCounts({ - setup, + apmEventClient, start, end, serviceGroups, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; serviceGroups: SavedServiceGroup[]; }) { - const { apmEventClient } = setup; - const serviceGroupsKueryMap: Record = serviceGroups.reduce((acc, sg) => { return { diff --git a/x-pack/plugins/apm/server/routes/service_groups/lookup_services.ts b/x-pack/plugins/apm/server/routes/service_groups/lookup_services.ts index 236b3e20222c2..4acfb49762629 100644 --- a/x-pack/plugins/apm/server/routes/service_groups/lookup_services.ts +++ b/x-pack/plugins/apm/server/routes/service_groups/lookup_services.ts @@ -13,23 +13,21 @@ import { SERVICE_ENVIRONMENT, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function lookupServices({ - setup, + apmEventClient, kuery, start, end, maxNumberOfServices, }: { - setup: Setup; + apmEventClient: APMEventClient; kuery: string; start: number; end: number; maxNumberOfServices: number; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search('lookup_services', { apm: { events: [ diff --git a/x-pack/plugins/apm/server/routes/service_groups/route.ts b/x-pack/plugins/apm/server/routes/service_groups/route.ts index 4430aaae760eb..4da84e6848696 100644 --- a/x-pack/plugins/apm/server/routes/service_groups/route.ts +++ b/x-pack/plugins/apm/server/routes/service_groups/route.ts @@ -7,7 +7,6 @@ import * as t from 'io-ts'; import { apmServiceGroupMaxNumberOfServices } from '@kbn/observability-plugin/common'; -import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { kueryRt, rangeRt } from '../default_api_types'; import { getServiceGroups } from './get_service_groups'; @@ -17,6 +16,7 @@ import { deleteServiceGroup } from './delete_service_group'; import { lookupServices } from './lookup_services'; import { SavedServiceGroup } from '../../../common/service_groups'; import { getServicesCounts } from './get_services_counts'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const serviceGroupsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/service-groups', @@ -57,7 +57,7 @@ const serviceGroupsWithServiceCountRoute = createApmServerRoute({ query: { start, end }, } = params; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const serviceGroups = await getServiceGroups({ savedObjectsClient, @@ -65,7 +65,7 @@ const serviceGroupsWithServiceCountRoute = createApmServerRoute({ return { servicesCounts: await getServicesCounts({ - setup, + apmEventClient, serviceGroups, start, end, @@ -164,12 +164,12 @@ const serviceGroupServicesRoute = createApmServerRoute({ const { uiSettings: { client: uiSettingsClient }, } = await context.core; - const [setup, maxNumberOfServices] = await Promise.all([ - setupRequest(resources), + const [apmEventClient, maxNumberOfServices] = await Promise.all([ + getApmEventClient(resources), uiSettingsClient.get(apmServiceGroupMaxNumberOfServices), ]); const items = await lookupServices({ - setup, + apmEventClient, kuery, start, end, diff --git a/x-pack/plugins/apm/server/routes/service_map/fetch_service_paths_from_trace_ids.ts b/x-pack/plugins/apm/server/routes/service_map/fetch_service_paths_from_trace_ids.ts index e5d97708ae173..5d044846da6e7 100644 --- a/x-pack/plugins/apm/server/routes/service_map/fetch_service_paths_from_trace_ids.ts +++ b/x-pack/plugins/apm/server/routes/service_map/fetch_service_paths_from_trace_ids.ts @@ -13,16 +13,14 @@ import { ExternalConnectionNode, ServiceConnectionNode, } from '../../../common/service_map'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function fetchServicePathsFromTraceIds( - setup: Setup, + apmEventClient: APMEventClient, traceIds: string[], start: number, end: number ) { - const { apmEventClient } = setup; - // make sure there's a range so ES can skip shards const dayInMs = 24 * 60 * 60 * 1000; const startRange = start - dayInMs; diff --git a/x-pack/plugins/apm/server/routes/service_map/get_service_map.ts b/x-pack/plugins/apm/server/routes/service_map/get_service_map.ts index 05424b4805d89..36a4218ae6e4a 100644 --- a/x-pack/plugins/apm/server/routes/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map/get_service_map.ts @@ -28,9 +28,11 @@ import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; import { ServiceGroup } from '../../../common/service_groups'; import { serviceGroupQuery } from '../../lib/service_group_query'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export interface IEnvOptions { setup: Setup; + apmEventClient: APMEventClient; serviceNames?: string[]; environment: string; searchAggregatedTransactions: boolean; @@ -42,6 +44,7 @@ export interface IEnvOptions { async function getConnectionData({ setup, + apmEventClient, serviceNames, environment, start, @@ -50,7 +53,8 @@ async function getConnectionData({ }: IEnvOptions) { return withApmSpan('get_service_map_connections', async () => { const { traceIds } = await getTraceSampleIds({ - setup, + config: setup.config, + apmEventClient, serviceNames, environment, start, @@ -75,7 +79,7 @@ async function getConnectionData({ Promise.all( chunks.map((traceIdsChunk) => getServiceMapFromTraceIds({ - setup, + apmEventClient, traceIds: traceIdsChunk, start, end, @@ -100,7 +104,7 @@ async function getServicesData( ) { const { environment, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -146,8 +150,6 @@ async function getServicesData( }, }; - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_service_stats_for_service_map', params diff --git a/x-pack/plugins/apm/server/routes/service_map/get_service_map_dependency_node_info.ts b/x-pack/plugins/apm/server/routes/service_map/get_service_map_dependency_node_info.ts index 8d2210827918a..241672a7fa4db 100644 --- a/x-pack/plugins/apm/server/routes/service_map/get_service_map_dependency_node_info.ts +++ b/x-pack/plugins/apm/server/routes/service_map/get_service_map_dependency_node_info.ts @@ -17,14 +17,14 @@ import { EventOutcome } from '../../../common/event_outcome'; import { environmentQuery } from '../../../common/utils/environment_query'; import { withApmSpan } from '../../utils/with_apm_span'; import { calculateThroughputWithRange } from '../../lib/helpers/calculate_throughput'; -import { Setup } from '../../lib/helpers/setup_request'; import { getBucketSize } from '../../lib/helpers/get_bucket_size'; import { getFailedTransactionRateTimeSeries } from '../../lib/helpers/transaction_error_rate'; import { NodeStats } from '../../../common/service_map'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; interface Options { - setup: Setup; + apmEventClient: APMEventClient; environment: string; dependencyName: string; start: number; @@ -35,13 +35,12 @@ interface Options { export function getServiceMapDependencyNodeInfo({ environment, dependencyName, - setup, + apmEventClient, start, end, offset, }: Options): Promise { return withApmSpan('get_service_map_dependency_node_stats', async () => { - const { apmEventClient } = setup; const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/service_map/get_service_map_from_trace_ids.ts b/x-pack/plugins/apm/server/routes/service_map/get_service_map_from_trace_ids.ts index 6a61a514881b0..21daa774152f3 100644 --- a/x-pack/plugins/apm/server/routes/service_map/get_service_map_from_trace_ids.ts +++ b/x-pack/plugins/apm/server/routes/service_map/get_service_map_from_trace_ids.ts @@ -7,7 +7,7 @@ import { find, uniqBy } from 'lodash'; import { Connection, ConnectionNode } from '../../../common/service_map'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { fetchServicePathsFromTraceIds } from './fetch_service_paths_from_trace_ids'; export function getConnections({ @@ -40,18 +40,18 @@ export function getConnections({ } export async function getServiceMapFromTraceIds({ - setup, + apmEventClient, traceIds, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; traceIds: string[]; start: number; end: number; }) { const serviceMapFromTraceIdsScriptResponse = - await fetchServicePathsFromTraceIds(setup, traceIds, start, end); + await fetchServicePathsFromTraceIds(apmEventClient, traceIds, start, end); const serviceMapScriptedAggValue = serviceMapFromTraceIdsScriptResponse.aggregations?.service_map.value; diff --git a/x-pack/plugins/apm/server/routes/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/routes/service_map/get_service_map_service_node_info.ts index 72e8b3b267cf2..7f4b260b83309 100644 --- a/x-pack/plugins/apm/server/routes/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/routes/service_map/get_service_map_service_node_info.ts @@ -24,7 +24,6 @@ import { import { environmentQuery } from '../../../common/utils/environment_query'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { getBucketSizeForAggregatedTransactions } from '../../lib/helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../../lib/helpers/setup_request'; import { getDocumentTypeFilterForTransactions, getDurationFieldForTransactions, @@ -36,9 +35,10 @@ import { percentCgroupMemoryUsedScript, percentSystemMemoryUsedScript, } from '../metrics/by_agent/shared/memory'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; interface Options { - setup: Setup; + apmEventClient: APMEventClient; environment: string; serviceName: string; searchAggregatedTransactions: boolean; @@ -53,7 +53,7 @@ interface TaskParameters { searchAggregatedTransactions: boolean; minutes: number; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; intervalString: string; @@ -65,7 +65,7 @@ interface TaskParameters { export function getServiceMapServiceNodeInfo({ environment, serviceName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -99,7 +99,7 @@ export function getServiceMapServiceNodeInfo({ searchAggregatedTransactions, minutes, serviceName, - setup, + apmEventClient, start: startWithOffset, end: endWithOffset, intervalString, @@ -125,7 +125,7 @@ export function getServiceMapServiceNodeInfo({ } async function getFailedTransactionsRateStats({ - setup, + apmEventClient, serviceName, environment, searchAggregatedTransactions, @@ -137,7 +137,7 @@ async function getFailedTransactionsRateStats({ return withApmSpan('get_error_rate_for_service_map_node', async () => { const { average, timeseries } = await getFailedTransactionRate({ environment, - setup, + apmEventClient, serviceName, searchAggregatedTransactions, start, @@ -154,7 +154,7 @@ async function getFailedTransactionsRateStats({ } async function getTransactionStats({ - setup, + apmEventClient, filter, minutes, searchAggregatedTransactions, @@ -163,8 +163,6 @@ async function getTransactionStats({ intervalString, offsetInMs, }: TaskParameters): Promise { - const { apmEventClient } = setup; - const durationField = getDurationFieldForTransactions( searchAggregatedTransactions ); @@ -241,15 +239,13 @@ async function getTransactionStats({ } async function getCpuStats({ - setup, + apmEventClient, filter, intervalString, start, end, offsetInMs, }: TaskParameters): Promise { - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_avg_cpu_usage_for_service_map_node', { @@ -295,7 +291,7 @@ async function getCpuStats({ } function getMemoryStats({ - setup, + apmEventClient, filter, intervalString, start, @@ -303,8 +299,6 @@ function getMemoryStats({ offsetInMs, }: TaskParameters) { return withApmSpan('get_memory_stats_for_service_map_node', async () => { - const { apmEventClient } = setup; - const getMemoryUsage = async ({ additionalFilters, script, diff --git a/x-pack/plugins/apm/server/routes/service_map/get_trace_sample_ids.ts b/x-pack/plugins/apm/server/routes/service_map/get_trace_sample_ids.ts index 76d15d06da0b7..2289d3df26485 100644 --- a/x-pack/plugins/apm/server/routes/service_map/get_trace_sample_ids.ts +++ b/x-pack/plugins/apm/server/routes/service_map/get_trace_sample_ids.ts @@ -18,29 +18,30 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { SERVICE_MAP_TIMEOUT_ERROR } from '../../../common/service_map'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; import { serviceGroupQuery } from '../../lib/service_group_query'; import { ServiceGroup } from '../../../common/service_groups'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import { APMConfig } from '../..'; const MAX_TRACES_TO_INSPECT = 1000; export async function getTraceSampleIds({ serviceNames, environment, - setup, + config, + apmEventClient, start, end, serviceGroup, }: { serviceNames?: string[]; environment: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; start: number; end: number; serviceGroup: ServiceGroup | null; }) { - const { apmEventClient, config } = setup; - const query = { bool: { filter: [...rangeQuery(start, end), ...serviceGroupQuery(serviceGroup)], diff --git a/x-pack/plugins/apm/server/routes/service_map/route.ts b/x-pack/plugins/apm/server/routes/service_map/route.ts index c2de9bf956a85..f833ce195c442 100644 --- a/x-pack/plugins/apm/server/routes/service_map/route.ts +++ b/x-pack/plugins/apm/server/routes/service_map/route.ts @@ -21,6 +21,7 @@ import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, rangeRt } from '../default_api_types'; import { getServiceGroup } from '../service_groups/get_service_group'; import { offsetRt } from '../../../common/comparison_rt'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const serviceMapRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/service-map', @@ -115,21 +116,23 @@ const serviceMapRoute = createApmServerRoute({ savedObjects: { client: savedObjectsClient }, uiSettings: { client: uiSettingsClient }, } = await context.core; - const [setup, serviceGroup, maxNumberOfServices] = await Promise.all([ - setupRequest(resources), - serviceGroupId - ? getServiceGroup({ - savedObjectsClient, - serviceGroupId, - }) - : Promise.resolve(null), - uiSettingsClient.get(apmServiceGroupMaxNumberOfServices), - ]); + const [setup, apmEventClient, serviceGroup, maxNumberOfServices] = + await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + serviceGroupId + ? getServiceGroup({ + savedObjectsClient, + serviceGroupId, + }) + : Promise.resolve(null), + uiSettingsClient.get(apmServiceGroupMaxNumberOfServices), + ]); const serviceNames = compact([serviceName]); const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -137,6 +140,7 @@ const serviceMapRoute = createApmServerRoute({ }); return getServiceMap({ setup, + apmEventClient, serviceNames, environment, searchAggregatedTransactions, @@ -176,7 +180,10 @@ const serviceMapServiceNodeRoute = createApmServerRoute({ if (!isActivePlatinumLicense(licensingContext.license)) { throw Boom.forbidden(invalidLicenseMessage); } - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { path: { serviceName }, @@ -184,7 +191,7 @@ const serviceMapServiceNodeRoute = createApmServerRoute({ } = params; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -193,7 +200,7 @@ const serviceMapServiceNodeRoute = createApmServerRoute({ const commonProps = { environment, - setup, + apmEventClient, serviceName, searchAggregatedTransactions, start, @@ -239,13 +246,19 @@ const serviceMapDependencyNodeRoute = createApmServerRoute({ if (!isActivePlatinumLicense(licensingContext.license)) { throw Boom.forbidden(invalidLicenseMessage); } - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { dependencyName, environment, start, end, offset }, } = params; - const commonProps = { environment, setup, dependencyName, start, end }; + const commonProps = { + environment, + apmEventClient, + dependencyName, + start, + end, + }; const [currentPeriod, previousPeriod] = await Promise.all([ getServiceMapDependencyNodeInfo(commonProps), diff --git a/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.test.ts b/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.test.ts index d763f1f913c4d..fef8a878f2e35 100644 --- a/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.test.ts +++ b/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.test.ts @@ -26,9 +26,9 @@ describe('getDerivedServiceAnnotations', () => { describe('with 0 versions', () => { it('returns no annotations', async () => { mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getDerivedServiceAnnotations({ - setup, + apmEventClient, serviceName: 'foo', environment: 'bar', searchAggregatedTransactions: false, @@ -54,9 +54,9 @@ describe('getDerivedServiceAnnotations', () => { describe('with 1 version', () => { it('returns no annotations', async () => { mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getDerivedServiceAnnotations({ - setup, + apmEventClient, serviceName: 'foo', environment: 'bar', searchAggregatedTransactions: false, @@ -87,9 +87,9 @@ describe('getDerivedServiceAnnotations', () => { versionsFirstSeen, ]; mock = await inspectSearchParams( - (setup) => + (setup, apmEventClient) => getDerivedServiceAnnotations({ - setup, + apmEventClient, serviceName: 'foo', environment: 'bar', searchAggregatedTransactions: false, diff --git a/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.ts index a718e9932661e..c98bc9dbeb17b 100644 --- a/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.ts +++ b/x-pack/plugins/apm/server/routes/services/annotations/get_derived_service_annotations.ts @@ -18,10 +18,10 @@ import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../../lib/helpers/transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getDerivedServiceAnnotations({ - setup, + apmEventClient, serviceName, environment, searchAggregatedTransactions, @@ -30,13 +30,11 @@ export async function getDerivedServiceAnnotations({ }: { serviceName: string; environment: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; }) { - const { apmEventClient } = setup; - const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), diff --git a/x-pack/plugins/apm/server/routes/services/annotations/index.test.ts b/x-pack/plugins/apm/server/routes/services/annotations/index.test.ts index a044648bd7a4f..729a2c16dd65e 100644 --- a/x-pack/plugins/apm/server/routes/services/annotations/index.test.ts +++ b/x-pack/plugins/apm/server/routes/services/annotations/index.test.ts @@ -10,11 +10,11 @@ import { } from '@kbn/observability-plugin/server'; import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { getServiceAnnotations } from '.'; -import { Setup } from '../../../lib/helpers/setup_request'; import * as GetDerivedServiceAnnotations from './get_derived_service_annotations'; import * as GetStoredAnnotations from './get_stored_annotations'; import { Annotation, AnnotationType } from '../../../../common/annotations'; import { errors } from '@elastic/elasticsearch'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; describe('getServiceAnnotations', () => { const storedAnnotations = [ @@ -60,7 +60,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }); expect(annotations).toEqual({ annotations: storedAnnotations, @@ -96,7 +96,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }); expect(annotations).toEqual({ annotations: storedAnnotations, @@ -133,7 +133,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }) ).rejects.toThrow('BOOM'); }); @@ -171,7 +171,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }); expect(annotations).toEqual({ annotations: [] }); }); @@ -206,7 +206,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }) ).rejects.toThrow('BOOM'); }); @@ -240,7 +240,7 @@ describe('getServiceAnnotations', () => { client: {} as ElasticsearchClient, logger: {} as Logger, annotationsClient: {} as ScopedAnnotationsClient, - setup: {} as Setup, + apmEventClient: {} as APMEventClient, }); expect(annotations).toEqual({ annotations: storedAnnotations, diff --git a/x-pack/plugins/apm/server/routes/services/annotations/index.ts b/x-pack/plugins/apm/server/routes/services/annotations/index.ts index cc103f2fe6cef..41f199f456d7d 100644 --- a/x-pack/plugins/apm/server/routes/services/annotations/index.ts +++ b/x-pack/plugins/apm/server/routes/services/annotations/index.ts @@ -7,12 +7,12 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { ScopedAnnotationsClient } from '@kbn/observability-plugin/server'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { getDerivedServiceAnnotations } from './get_derived_service_annotations'; import { getStoredAnnotations } from './get_stored_annotations'; export async function getServiceAnnotations({ - setup, + apmEventClient, searchAggregatedTransactions, serviceName, environment, @@ -24,7 +24,7 @@ export async function getServiceAnnotations({ }: { serviceName: string; environment: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; annotationsClient?: ScopedAnnotationsClient; client: ElasticsearchClient; @@ -38,7 +38,7 @@ export async function getServiceAnnotations({ // start fetching derived annotations (based on transactions), but don't wait on it // it will likely be significantly slower than the stored annotations const derivedAnnotationsPromise = getDerivedServiceAnnotations({ - setup, + apmEventClient, serviceName, environment, searchAggregatedTransactions, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_agent.ts b/x-pack/plugins/apm/server/routes/services/get_service_agent.ts index 78b68f3a88ba4..e848dd9befbfb 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_agent.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_agent.ts @@ -12,7 +12,7 @@ import { SERVICE_NAME, SERVICE_RUNTIME_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; interface ServiceAgent { agent?: { @@ -27,17 +27,15 @@ interface ServiceAgent { export async function getServiceAgent({ serviceName, - setup, + apmEventClient, start, end, }: { serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { terminate_after: 1, apm: { diff --git a/x-pack/plugins/apm/server/routes/services/get_service_dependencies.ts b/x-pack/plugins/apm/server/routes/services/get_service_dependencies.ts index cf60502e9861b..e0878a9361f30 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_dependencies.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_dependencies.ts @@ -9,10 +9,10 @@ import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; import { getConnectionStats } from '../../lib/connections/get_connection_stats'; import { getConnectionStatsItemsWithRelativeImpact } from '../../lib/connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceDependencies({ - setup, + apmEventClient, start, end, serviceName, @@ -20,7 +20,7 @@ export async function getServiceDependencies({ environment, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; serviceName: string; @@ -29,7 +29,7 @@ export async function getServiceDependencies({ offset?: string; }) { const statsItems = await getConnectionStats({ - setup, + apmEventClient, start, end, numBuckets, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_dependencies_breakdown.ts b/x-pack/plugins/apm/server/routes/services/get_service_dependencies_breakdown.ts index 4fc7667fa2349..8b940b8525b66 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_dependencies_breakdown.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_dependencies_breakdown.ts @@ -9,18 +9,18 @@ import { kqlQuery } from '@kbn/observability-plugin/server'; import { getNodeName } from '../../../common/connections'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../../lib/helpers/setup_request'; import { getConnectionStats } from '../../lib/connections/get_connection_stats'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceDependenciesBreakdown({ - setup, + apmEventClient, start, end, serviceName, environment, kuery, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; serviceName: string; @@ -28,7 +28,7 @@ export async function getServiceDependenciesBreakdown({ kuery: string; }) { const items = await getConnectionStats({ - setup, + apmEventClient, start, end, numBuckets: 100, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instance_metadata_details.ts b/x-pack/plugins/apm/server/routes/services/get_service_instance_metadata_details.ts index c69ea36d3f236..22893a5acefd3 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instance_metadata_details.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instance_metadata_details.ts @@ -12,27 +12,26 @@ import { SERVICE_NAME, SERVICE_NODE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; import { maybe } from '../../../common/utils/maybe'; import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../lib/helpers/transactions'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceInstanceMetadataDetails({ serviceName, serviceNodeName, - setup, + apmEventClient, start, end, }: { serviceName: string; serviceNodeName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { - const { apmEventClient } = setup; const filter = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [SERVICE_NODE_NAME]: serviceNodeName } }, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instances/detailed_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_service_instances/detailed_statistics.ts index 01e82c6d57c77..2d23345c3ba1b 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instances/detailed_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instances/detailed_statistics.ts @@ -11,15 +11,15 @@ import { Coordinate } from '../../../../typings/timeseries'; import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; import { joinByKey } from '../../../../common/utils/join_by_key'; import { withApmSpan } from '../../../utils/with_apm_span'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getServiceInstancesSystemMetricStatistics } from './get_service_instances_system_metric_statistics'; import { getServiceInstancesTransactionStatistics } from './get_service_instances_transaction_statistics'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; interface ServiceInstanceDetailedStatisticsParams { environment: string; kuery: string; latencyAggregationType: LatencyAggregationType; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; transactionType: string; searchAggregatedTransactions: boolean; @@ -67,7 +67,7 @@ export async function getServiceInstancesDetailedStatisticsPeriods({ environment, kuery, latencyAggregationType, - setup, + apmEventClient, serviceName, transactionType, searchAggregatedTransactions, @@ -80,7 +80,7 @@ export async function getServiceInstancesDetailedStatisticsPeriods({ environment: string; kuery: string; latencyAggregationType: LatencyAggregationType; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; transactionType: string; searchAggregatedTransactions: boolean; @@ -97,7 +97,7 @@ export async function getServiceInstancesDetailedStatisticsPeriods({ environment, kuery, latencyAggregationType, - setup, + apmEventClient, serviceName, transactionType, searchAggregatedTransactions, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_system_metric_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_system_metric_statistics.ts index 7e899f4140c15..71e1b2f7658c1 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_system_metric_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_system_metric_statistics.ts @@ -20,7 +20,7 @@ import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; import { Coordinate } from '../../../../typings/timeseries'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { getBucketSize } from '../../../lib/helpers/get_bucket_size'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { percentCgroupMemoryUsedScript, percentSystemMemoryUsedScript, @@ -48,7 +48,7 @@ export async function getServiceInstancesSystemMetricStatistics< >({ environment, kuery, - setup, + apmEventClient, serviceName, size, start, @@ -58,7 +58,7 @@ export async function getServiceInstancesSystemMetricStatistics< isComparisonSearch, offset, }: { - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; start: number; end: number; @@ -70,8 +70,6 @@ export async function getServiceInstancesSystemMetricStatistics< isComparisonSearch: T; offset?: string; }): Promise>> { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_transaction_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_transaction_statistics.ts index 464b4c07ec58d..8bff6b47308bc 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_transaction_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instances/get_service_instances_transaction_statistics.ts @@ -27,8 +27,8 @@ import { getLatencyAggregation, getLatencyValue, } from '../../../lib/helpers/latency_aggregation_type'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; interface ServiceInstanceTransactionPrimaryStatistics { serviceNodeName: string; @@ -54,7 +54,7 @@ export async function getServiceInstancesTransactionStatistics< environment, kuery, latencyAggregationType, - setup, + apmEventClient, transactionType, serviceName, size, @@ -67,7 +67,7 @@ export async function getServiceInstancesTransactionStatistics< offset, }: { latencyAggregationType: LatencyAggregationType; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; transactionType: string; searchAggregatedTransactions: boolean; @@ -81,8 +81,6 @@ export async function getServiceInstancesTransactionStatistics< numBuckets?: number; offset?: string; }): Promise>> { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instances/main_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_service_instances/main_statistics.ts index a09b105cb5a79..095f3c981a689 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instances/main_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instances/main_statistics.ts @@ -8,7 +8,7 @@ import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; import { joinByKey } from '../../../../common/utils/join_by_key'; import { withApmSpan } from '../../../utils/with_apm_span'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { getServiceInstancesSystemMetricStatistics } from './get_service_instances_system_metric_statistics'; import { getServiceInstancesTransactionStatistics } from './get_service_instances_transaction_statistics'; @@ -16,7 +16,7 @@ interface ServiceInstanceMainStatisticsParams { environment: string; kuery: string; latencyAggregationType: LatencyAggregationType; - setup: Setup; + apmEventClient: APMEventClient; serviceName: string; transactionType: string; searchAggregatedTransactions: boolean; diff --git a/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts b/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts index a7014d65b7182..40e48101784c4 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts @@ -28,7 +28,7 @@ import { import { ContainerType } from '../../../common/service_metadata'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { should } from './get_service_metadata_icons'; type ServiceMetadataDetailsRaw = Pick< @@ -78,19 +78,17 @@ export interface ServiceMetadataDetails { export async function getServiceMetadataDetails({ serviceName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, }: { serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; }): Promise { - const { apmEventClient } = setup; - const filter = [ { term: { [SERVICE_NAME]: serviceName } }, ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/routes/services/get_service_metadata_icons.ts b/x-pack/plugins/apm/server/routes/services/get_service_metadata_icons.ts index 7cf5304ded844..6b6ee0489ad19 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_metadata_icons.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_metadata_icons.ts @@ -20,7 +20,7 @@ import { import { ContainerType } from '../../../common/service_metadata'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; type ServiceMetadataIconsRaw = Pick< TransactionRaw, @@ -44,19 +44,17 @@ export const should = [ export async function getServiceMetadataIcons({ serviceName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, }: { serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; }): Promise { - const { apmEventClient } = setup; - const filter = [ { term: { [SERVICE_NAME]: serviceName } }, ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts b/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts index 7a8e786c2912b..227dcab3deb41 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts @@ -7,7 +7,6 @@ import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../lib/helpers/setup_request'; import { HOST_NAME, CONTAINER_ID, @@ -22,24 +21,23 @@ import { serviceNodeNameQuery, } from '../../../common/utils/environment_query'; import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceNodeMetadata({ kuery, serviceName, serviceNodeName, - setup, + apmEventClient, start, end, }: { kuery: string; serviceName: string; serviceNodeName: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { apm: { events: [ProcessorEvent.metric], diff --git a/x-pack/plugins/apm/server/routes/services/get_service_transaction_group_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_service_transaction_group_detailed_statistics.ts index df02ba0647483..5e8c5b0cc1c55 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_transaction_group_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_transaction_group_detailed_statistics.ts @@ -28,16 +28,16 @@ import { getLatencyAggregation, getLatencyValue, } from '../../lib/helpers/latency_aggregation_type'; -import { Setup } from '../../lib/helpers/setup_request'; import { calculateFailedTransactionRate } from '../../lib/helpers/transaction_error_rate'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceTransactionGroupDetailedStatistics({ environment, kuery, serviceName, transactionNames, - setup, + apmEventClient, numBuckets, searchAggregatedTransactions, transactionType, @@ -50,7 +50,7 @@ export async function getServiceTransactionGroupDetailedStatistics({ kuery: string; serviceName: string; transactionNames: string[]; - setup: Setup; + apmEventClient: APMEventClient; numBuckets: number; searchAggregatedTransactions: boolean; transactionType: string; @@ -67,8 +67,6 @@ export async function getServiceTransactionGroupDetailedStatistics({ impact: number; }> > { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -185,7 +183,7 @@ export async function getServiceTransactionGroupDetailedStatistics({ export async function getServiceTransactionGroupDetailedStatisticsPeriods({ serviceName, transactionNames, - setup, + apmEventClient, numBuckets, searchAggregatedTransactions, transactionType, @@ -198,7 +196,7 @@ export async function getServiceTransactionGroupDetailedStatisticsPeriods({ }: { serviceName: string; transactionNames: string[]; - setup: Setup; + apmEventClient: APMEventClient; numBuckets: number; searchAggregatedTransactions: boolean; transactionType: string; @@ -210,7 +208,7 @@ export async function getServiceTransactionGroupDetailedStatisticsPeriods({ offset?: string; }) { const commonProps = { - setup, + apmEventClient, serviceName, transactionNames, searchAggregatedTransactions, diff --git a/x-pack/plugins/apm/server/routes/services/get_service_transaction_groups.ts b/x-pack/plugins/apm/server/routes/services/get_service_transaction_groups.ts index 4a589f96b68f1..7b828d91af9a0 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_transaction_groups.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_transaction_groups.ts @@ -25,8 +25,9 @@ import { getLatencyAggregation, getLatencyValue, } from '../../lib/helpers/latency_aggregation_type'; -import { Setup } from '../../lib/helpers/setup_request'; import { calculateFailedTransactionRate } from '../../lib/helpers/transaction_error_rate'; +import { APMConfig } from '../..'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export type ServiceOverviewTransactionGroupSortField = | 'name' @@ -39,7 +40,8 @@ export async function getServiceTransactionGroups({ environment, kuery, serviceName, - setup, + config, + apmEventClient, searchAggregatedTransactions, transactionType, latencyAggregationType, @@ -49,14 +51,14 @@ export async function getServiceTransactionGroups({ environment: string; kuery: string; serviceName: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; transactionType: string; latencyAggregationType: LatencyAggregationType; start: number; end: number; }) { - const { apmEventClient, config } = setup; const bucketSize = config.ui.transactionGroupBucketSize; const field = getDurationFieldForTransactions(searchAggregatedTransactions); diff --git a/x-pack/plugins/apm/server/routes/services/get_service_transaction_types.ts b/x-pack/plugins/apm/server/routes/services/get_service_transaction_types.ts index 73d53a24d4f24..1081c35b7eb70 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_transaction_types.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_transaction_types.ts @@ -10,27 +10,25 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../lib/helpers/transactions'; export async function getServiceTransactionTypes({ - setup, + apmEventClient, serviceName, searchAggregatedTransactions, start, end, }: { serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; }) { - const { apmEventClient } = setup; - const params = { apm: { events: [getProcessorEventForTransactions(searchAggregatedTransactions)], diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_service_aggregated_transaction_stats.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_service_aggregated_transaction_stats.ts index d7282dfd2db85..73436ad9afb67 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_service_aggregated_transaction_stats.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_service_aggregated_transaction_stats.ts @@ -24,15 +24,15 @@ import { environmentQuery } from '../../../../common/utils/environment_query'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { calculateThroughputWithRange } from '../../../lib/helpers/calculate_throughput'; import { calculateFailedTransactionRateFromServiceMetrics } from '../../../lib/helpers/transaction_error_rate'; -import { ServicesItemsSetup } from './get_services_items'; import { serviceGroupQuery } from '../../../lib/service_group_query'; import { ServiceGroup } from '../../../../common/service_groups'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; import { getDocumentTypeFilterForServiceMetrics } from '../../../lib/helpers/service_metrics'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; interface AggregationParams { environment: string; kuery: string; - setup: ServicesItemsSetup; + apmEventClient: APMEventClient; maxNumServices: number; start: number; end: number; @@ -43,15 +43,13 @@ interface AggregationParams { export async function getServiceAggregatedTransactionStats({ environment, kuery, - setup, + apmEventClient, maxNumServices, start, end, serviceGroup, randomSampler, }: AggregationParams) { - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_service_aggregated_transaction_stats', { diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts index 0d0d831b61a1e..ba5903133e445 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts @@ -28,15 +28,15 @@ import { calculateFailedTransactionRate, getOutcomeAggregation, } from '../../../lib/helpers/transaction_error_rate'; -import { ServicesItemsSetup } from './get_services_items'; import { serviceGroupQuery } from '../../../lib/service_group_query'; import { ServiceGroup } from '../../../../common/service_groups'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; interface AggregationParams { environment: string; kuery: string; - setup: ServicesItemsSetup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; maxNumServices: number; start: number; @@ -48,7 +48,7 @@ interface AggregationParams { export async function getServiceTransactionStats({ environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, maxNumServices, start, @@ -56,8 +56,6 @@ export async function getServiceTransactionStats({ serviceGroup, randomSampler, }: AggregationParams) { - const { apmEventClient } = setup; - const outcomes = getOutcomeAggregation(); const metrics = { diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_services_from_error_and_metric_documents.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_services_from_error_and_metric_documents.ts index 92cb6396856d8..7ae1698b988dd 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_services_from_error_and_metric_documents.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_services_from_error_and_metric_documents.ts @@ -14,14 +14,14 @@ import { SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; -import { Setup } from '../../../lib/helpers/setup_request'; import { serviceGroupQuery } from '../../../lib/service_group_query'; import { ServiceGroup } from '../../../../common/service_groups'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServicesFromErrorAndMetricDocuments({ environment, - setup, + apmEventClient, maxNumServices, kuery, start, @@ -29,7 +29,7 @@ export async function getServicesFromErrorAndMetricDocuments({ serviceGroup, randomSampler, }: { - setup: Setup; + apmEventClient: APMEventClient; environment: string; maxNumServices: number; kuery: string; @@ -38,8 +38,6 @@ export async function getServicesFromErrorAndMetricDocuments({ serviceGroup: ServiceGroup | null; randomSampler: RandomSampler; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_services_from_error_and_metric_documents', { diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_services_items.ts index 7ee41a2bea0e0..e3d2b72ec56b2 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_services_items.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_services_items.ts @@ -15,6 +15,7 @@ import { getServiceAggregatedTransactionStats } from './get_service_aggregated_t import { mergeServiceStats } from './merge_service_stats'; import { ServiceGroup } from '../../../../common/service_groups'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export type ServicesItemsSetup = Setup; @@ -24,6 +25,7 @@ export async function getServicesItems({ environment, kuery, setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, logger, @@ -35,6 +37,7 @@ export async function getServicesItems({ environment: string; kuery: string; setup: ServicesItemsSetup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; searchAggregatedServiceMetrics: boolean; logger: Logger; @@ -44,10 +47,9 @@ export async function getServicesItems({ randomSampler: RandomSampler; }) { return withApmSpan('get_services_items', async () => { - const params = { + const commonParams = { environment, kuery, - setup, searchAggregatedTransactions, searchAggregatedServiceMetrics, maxNumServices: MAX_NUMBER_OF_SERVICES, @@ -63,10 +65,19 @@ export async function getServicesItems({ healthStatuses, ] = await Promise.all([ searchAggregatedServiceMetrics - ? getServiceAggregatedTransactionStats(params) - : getServiceTransactionStats(params), - getServicesFromErrorAndMetricDocuments(params), - getHealthStatuses(params).catch((err) => { + ? getServiceAggregatedTransactionStats({ + ...commonParams, + apmEventClient, + }) + : getServiceTransactionStats({ + ...commonParams, + apmEventClient, + }), + getServicesFromErrorAndMetricDocuments({ + ...commonParams, + apmEventClient, + }), + getHealthStatuses({ ...commonParams, setup }).catch((err) => { logger.error(err); return []; }), diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_sorted_and_filtered_services.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_sorted_and_filtered_services.ts index a006c5b02509d..62748c722ffee 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_sorted_and_filtered_services.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_sorted_and_filtered_services.ts @@ -7,6 +7,7 @@ import { Logger } from '@kbn/logging'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; import { Environment } from '../../../../common/environment_rt'; @@ -16,8 +17,42 @@ import { Setup } from '../../../lib/helpers/setup_request'; import { getHealthStatuses } from './get_health_statuses'; import { lookupServices } from '../../service_groups/lookup_services'; +export async function getServiceNamesFromTermsEnum({ + apmEventClient, + environment, + maxNumberOfServices, +}: { + apmEventClient: APMEventClient; + environment: Environment; + maxNumberOfServices: number; +}) { + if (environment !== ENVIRONMENT_ALL.value) { + return []; + } + const response = await apmEventClient.termsEnum( + 'get_services_from_terms_enum', + { + apm: { + events: [ + ProcessorEvent.transaction, + ProcessorEvent.span, + ProcessorEvent.metric, + ProcessorEvent.error, + ], + }, + body: { + size: maxNumberOfServices, + field: SERVICE_NAME, + }, + } + ); + + return response.terms; +} + export async function getSortedAndFilteredServices({ setup, + apmEventClient, start, end, environment, @@ -26,6 +61,7 @@ export async function getSortedAndFilteredServices({ maxNumberOfServices, }: { setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: Environment; @@ -33,33 +69,6 @@ export async function getSortedAndFilteredServices({ serviceGroup: ServiceGroup | null; maxNumberOfServices: number; }) { - const { apmEventClient } = setup; - - async function getServiceNamesFromTermsEnum() { - if (environment !== ENVIRONMENT_ALL.value) { - return []; - } - const response = await apmEventClient.termsEnum( - 'get_services_from_terms_enum', - { - apm: { - events: [ - ProcessorEvent.transaction, - ProcessorEvent.span, - ProcessorEvent.metric, - ProcessorEvent.error, - ], - }, - body: { - size: maxNumberOfServices, - field: SERVICE_NAME, - }, - } - ); - - return response.terms; - } - const [servicesWithHealthStatuses, selectedServices] = await Promise.all([ getHealthStatuses({ setup, @@ -72,13 +81,17 @@ export async function getSortedAndFilteredServices({ }), serviceGroup ? getServiceNamesFromServiceGroup({ - setup, + apmEventClient, start, end, maxNumberOfServices, serviceGroup, }) - : getServiceNamesFromTermsEnum(), + : getServiceNamesFromTermsEnum({ + apmEventClient, + environment, + maxNumberOfServices, + }), ]); const services = joinByKey( @@ -93,20 +106,20 @@ export async function getSortedAndFilteredServices({ } async function getServiceNamesFromServiceGroup({ - setup, + apmEventClient, start, end, maxNumberOfServices, serviceGroup: { kuery }, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; maxNumberOfServices: number; serviceGroup: ServiceGroup; }) { const services = await lookupServices({ - setup, + apmEventClient, kuery, start, end, diff --git a/x-pack/plugins/apm/server/routes/services/get_services/index.ts b/x-pack/plugins/apm/server/routes/services/get_services/index.ts index 83932f630357e..d9eca887c8e08 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/index.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/index.ts @@ -11,11 +11,13 @@ import { Setup } from '../../../lib/helpers/setup_request'; import { getServicesItems } from './get_services_items'; import { ServiceGroup } from '../../../../common/service_groups'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServices({ environment, kuery, setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, logger, @@ -27,6 +29,7 @@ export async function getServices({ environment: string; kuery: string; setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; searchAggregatedServiceMetrics: boolean; logger: Logger; @@ -40,6 +43,7 @@ export async function getServices({ environment, kuery, setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, logger, diff --git a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_aggregated_transaction_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_aggregated_transaction_detailed_statistics.ts index 83df6d0773d73..f6ae0b220ee43 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_aggregated_transaction_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_aggregated_transaction_detailed_statistics.ts @@ -24,16 +24,16 @@ import { environmentQuery } from '../../../../common/utils/environment_query'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; import { calculateThroughputWithRange } from '../../../lib/helpers/calculate_throughput'; import { getBucketSizeForAggregatedTransactions } from '../../../lib/helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; import { calculateFailedTransactionRateFromServiceMetrics } from '../../../lib/helpers/transaction_error_rate'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; import { getDocumentTypeFilterForServiceMetrics } from '../../../lib/helpers/service_metrics'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceAggregatedTransactionDetailedStats({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedServiceMetrics, offset, start, @@ -43,14 +43,13 @@ export async function getServiceAggregatedTransactionDetailedStats({ serviceNames: string[]; environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedServiceMetrics: boolean; offset?: string; start: number; end: number; randomSampler: RandomSampler; }) { - const { apmEventClient } = setup; const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -185,7 +184,7 @@ export async function getServiceAggregatedDetailedStatsPeriods({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedServiceMetrics, offset, start, @@ -195,7 +194,7 @@ export async function getServiceAggregatedDetailedStatsPeriods({ serviceNames: string[]; environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedServiceMetrics: boolean; offset?: string; start: number; @@ -207,7 +206,7 @@ export async function getServiceAggregatedDetailedStatsPeriods({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedServiceMetrics, start, end, diff --git a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts index c587b3711e58a..fbddad6aa1c42 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/get_service_transaction_detailed_statistics.ts @@ -25,18 +25,18 @@ import { } from '../../../lib/helpers/transactions'; import { calculateThroughputWithRange } from '../../../lib/helpers/calculate_throughput'; import { getBucketSizeForAggregatedTransactions } from '../../../lib/helpers/get_bucket_size_for_aggregated_transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; import { calculateFailedTransactionRate, getOutcomeAggregation, } from '../../../lib/helpers/transaction_error_rate'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServiceTransactionDetailedStats({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, offset, start, @@ -46,14 +46,13 @@ export async function getServiceTransactionDetailedStats({ serviceNames: string[]; environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; offset?: string; start: number; end: number; randomSampler: RandomSampler; }) { - const { apmEventClient } = setup; const { offsetInMs, startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -182,7 +181,7 @@ export async function getServiceDetailedStatsPeriods({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, offset, start, @@ -192,7 +191,7 @@ export async function getServiceDetailedStatsPeriods({ serviceNames: string[]; environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; offset?: string; start: number; @@ -204,7 +203,7 @@ export async function getServiceDetailedStatsPeriods({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, start, end, diff --git a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/index.ts b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/index.ts index b142b3484d559..583bb6e938aad 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/index.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services_detailed_statistics/index.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { Setup } from '../../../lib/helpers/setup_request'; import { getServiceDetailedStatsPeriods } from './get_service_transaction_detailed_statistics'; import { getServiceAggregatedDetailedStatsPeriods } from './get_service_aggregated_transaction_detailed_statistics'; import { RandomSampler } from '../../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getServicesDetailedStatistics({ serviceNames, environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, offset, @@ -25,7 +25,7 @@ export async function getServicesDetailedStatistics({ serviceNames: string[]; environment: string; kuery: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; searchAggregatedServiceMetrics: boolean; offset?: string; @@ -37,7 +37,7 @@ export async function getServicesDetailedStatistics({ serviceNames, environment, kuery, - setup, + apmEventClient, start, end, randomSampler, diff --git a/x-pack/plugins/apm/server/routes/services/get_throughput.ts b/x-pack/plugins/apm/server/routes/services/get_throughput.ts index a4312b6dca896..5413bcbf56322 100644 --- a/x-pack/plugins/apm/server/routes/services/get_throughput.ts +++ b/x-pack/plugins/apm/server/routes/services/get_throughput.ts @@ -20,16 +20,16 @@ import { getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../lib/helpers/transactions'; -import { Setup } from '../../lib/helpers/setup_request'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { getBucketSizeForAggregatedTransactions } from '../../lib/helpers/get_bucket_size_for_aggregated_transactions'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; interface Options { environment: string; kuery: string; searchAggregatedTransactions: boolean; serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; transactionType: string; transactionName?: string; start: number; @@ -42,15 +42,13 @@ export async function getThroughput({ kuery, searchAggregatedTransactions, serviceName, - setup, + apmEventClient, transactionType, transactionName, start, end, offset, }: Options) { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, diff --git a/x-pack/plugins/apm/server/routes/services/queries.test.ts b/x-pack/plugins/apm/server/routes/services/queries.test.ts index ff9f79867c2d7..1410772704648 100644 --- a/x-pack/plugins/apm/server/routes/services/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/services/queries.test.ts @@ -23,10 +23,10 @@ describe('services queries', () => { }); it('fetches the service agent name', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getServiceAgent({ serviceName: 'foo', - setup, + apmEventClient, start: 0, end: 50000, }) @@ -36,10 +36,10 @@ describe('services queries', () => { }); it('fetches the service transaction types', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getServiceTransactionTypes({ serviceName: 'foo', - setup, + apmEventClient, searchAggregatedTransactions: false, start: 0, end: 50000, @@ -50,9 +50,10 @@ describe('services queries', () => { }); it('fetches the service items', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getServicesItems({ setup, + apmEventClient, searchAggregatedTransactions: false, searchAggregatedServiceMetrics: false, logger: {} as any, @@ -74,7 +75,9 @@ describe('services queries', () => { }); it('fetches the agent status', async () => { - mock = await inspectSearchParams((setup) => hasHistoricalAgentData(setup)); + mock = await inspectSearchParams((setup, apmEventClient) => + hasHistoricalAgentData(apmEventClient) + ); expect(mock.params).toMatchSnapshot(); }); diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 1f1cac260331f..0dc2de2d68b45 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -56,6 +56,7 @@ import { getServiceGroup } from '../service_groups/get_service_group'; import { offsetRt } from '../../../common/comparison_rt'; import { getRandomSampler } from '../../lib/helpers/get_random_sampler'; import { createInfraMetricsClient } from '../../lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const servicesRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/services', @@ -126,15 +127,17 @@ const servicesRoute = createApmServerRoute({ const savedObjectsClient = (await context.core).savedObjects.client; const coreContext = await resources.context.core; - const [setup, serviceGroup, randomSampler] = await Promise.all([ - setupRequest(resources), - serviceGroupId - ? getServiceGroup({ savedObjectsClient, serviceGroupId }) - : Promise.resolve(null), - getRandomSampler({ security, request, probability }), - ]); + const [setup, apmEventClient, serviceGroup, randomSampler] = + await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + serviceGroupId + ? getServiceGroup({ savedObjectsClient, serviceGroupId }) + : Promise.resolve(null), + getRandomSampler({ security, request, probability }), + ]); - const { apmEventClient, config } = setup; + const { config } = setup; const serviceMetricsEnabled = await coreContext.uiSettings.client.get(enableServiceMetrics); @@ -153,6 +156,7 @@ const servicesRoute = createApmServerRoute({ environment, kuery, setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, logger, @@ -223,12 +227,13 @@ const servicesDetailedStatisticsRoute = createApmServerRoute({ const { serviceNames } = params.body; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); - const { apmEventClient, config } = setup; + const { config } = setup; const serviceMetricsEnabled = await coreContext.uiSettings.client.get(enableServiceMetrics); @@ -250,7 +255,7 @@ const servicesDetailedStatisticsRoute = createApmServerRoute({ return getServicesDetailedStatistics({ environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, searchAggregatedServiceMetrics, offset, @@ -274,14 +279,17 @@ const serviceMetadataDetailsRoute = createApmServerRoute({ ): Promise< import('./get_service_metadata_details').ServiceMetadataDetails > => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const infraMetricsClient = createInfraMetricsClient(resources); const { params } = resources; const { serviceName } = params.path; const { start, end } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -290,7 +298,7 @@ const serviceMetadataDetailsRoute = createApmServerRoute({ const serviceMetadataDetails = await getServiceMetadataDetails({ serviceName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -321,13 +329,16 @@ const serviceMetadataIconsRoute = createApmServerRoute({ handler: async ( resources ): Promise => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; const { start, end } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -336,7 +347,7 @@ const serviceMetadataIconsRoute = createApmServerRoute({ return getServiceMetadataIcons({ serviceName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -359,14 +370,14 @@ const serviceAgentRoute = createApmServerRoute({ | { agentName?: undefined; runtimeName?: undefined } | { agentName: string | undefined; runtimeName: string | undefined } > => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { start, end } = params.query; return getServiceAgent({ serviceName, - setup, + apmEventClient, start, end, }); @@ -383,16 +394,19 @@ const serviceTransactionTypesRoute = createApmServerRoute({ }), options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ transactionTypes: string[] }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; const { start, end } = params.query; return getServiceTransactionTypes({ serviceName, - setup, + apmEventClient, searchAggregatedTransactions: await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -418,14 +432,14 @@ const serviceNodeMetadataRoute = createApmServerRoute({ handler: async ( resources ): Promise<{ host: string | number; containerId: string | number }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName, serviceNodeName } = params.path; const { kuery, start, end } = params.query; return getServiceNodeMetadata({ kuery, - setup, + apmEventClient, serviceName, serviceNodeName, start, @@ -448,7 +462,10 @@ const serviceAnnotationsRoute = createApmServerRoute({ ): Promise<{ annotations: Array; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params, plugins, context, request, logger } = resources; const { serviceName } = params.path; const { environment, start, end } = params.query; @@ -466,7 +483,7 @@ const serviceAnnotationsRoute = createApmServerRoute({ ) : undefined, getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, start, end, @@ -477,7 +494,7 @@ const serviceAnnotationsRoute = createApmServerRoute({ return getServiceAnnotations({ environment, - setup, + apmEventClient, searchAggregatedTransactions, serviceName, annotationsClient, @@ -586,7 +603,10 @@ const serviceThroughputRoute = createApmServerRoute({ y: import('./../../../typings/common').Maybe; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; const { @@ -599,7 +619,8 @@ const serviceThroughputRoute = createApmServerRoute({ end, } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -610,7 +631,7 @@ const serviceThroughputRoute = createApmServerRoute({ kuery, searchAggregatedTransactions, serviceName, - setup, + apmEventClient, transactionType, transactionName, }; @@ -680,7 +701,10 @@ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ memoryUsage?: number | null | undefined; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; const { @@ -694,7 +718,8 @@ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -706,7 +731,7 @@ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ kuery, latencyAggregationType, serviceName, - setup, + apmEventClient, transactionType, searchAggregatedTransactions, start, @@ -719,7 +744,7 @@ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ kuery, latencyAggregationType, serviceName, - setup, + apmEventClient, transactionType, searchAggregatedTransactions, start, @@ -800,7 +825,10 @@ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({ serviceNodeName: string; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; const { @@ -816,7 +844,8 @@ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({ } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + apmEventClient, + config: setup.config, kuery, start, end, @@ -827,7 +856,7 @@ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({ kuery, latencyAggregationType, serviceName, - setup, + apmEventClient, transactionType, searchAggregatedTransactions, numBuckets, @@ -901,7 +930,7 @@ export const serviceInstancesMetadataDetails = createApmServerRoute({ | import('./../../../typings/es_schemas/raw/fields/cloud').Cloud | undefined; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const infraMetricsClient = createInfraMetricsClient(resources); const { params } = resources; const { serviceName, serviceNodeName } = params.path; @@ -909,7 +938,7 @@ export const serviceInstancesMetadataDetails = createApmServerRoute({ const serviceInstanceMetadataDetails = await getServiceInstanceMetadataDetails({ - setup, + apmEventClient, serviceName, serviceNodeName, start, @@ -1002,13 +1031,13 @@ export const serviceDependenciesRoute = createApmServerRoute({ location: import('./../../../common/connections').Node; }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { environment, numBuckets, start, end, offset } = params.query; const opts = { - setup, + apmEventClient, start, end, serviceName, @@ -1061,13 +1090,13 @@ export const serviceDependenciesBreakdownRoute = createApmServerRoute({ ): Promise<{ breakdown: Array<{ title: string; data: Array<{ x: number; y: number }> }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { environment, start, end, kuery } = params.query; const breakdown = await getServiceDependenciesBreakdown({ - setup, + apmEventClient, start, end, serviceName, @@ -1177,16 +1206,19 @@ const sortedAndFilteredServicesRoute = createApmServerRoute({ uiSettings: { client: uiSettingsClient }, } = await resources.context.core; - const [setup, serviceGroup, maxNumberOfServices] = await Promise.all([ - setupRequest(resources), - serviceGroupId - ? getServiceGroup({ savedObjectsClient, serviceGroupId }) - : Promise.resolve(null), - uiSettingsClient.get(apmServiceGroupMaxNumberOfServices), - ]); + const [setup, apmEventClient, serviceGroup, maxNumberOfServices] = + await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + serviceGroupId + ? getServiceGroup({ savedObjectsClient, serviceGroupId }) + : Promise.resolve(null), + uiSettingsClient.get(apmServiceGroupMaxNumberOfServices), + ]); return { services: await getSortedAndFilteredServices({ setup, + apmEventClient, start, end, environment, diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_agent_name_by_service.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_agent_name_by_service.ts index f70bd330bfc3e..1ebc98877941f 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_agent_name_by_service.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_agent_name_by_service.ts @@ -6,19 +6,17 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../../lib/helpers/setup_request'; import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { AGENT_NAME } from '../../../../common/elasticsearch_fieldnames'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getAgentNameByService({ serviceName, - setup, + apmEventClient, }: { serviceName: string; - setup: Setup; + apmEventClient: APMEventClient; }) { - const { apmEventClient } = setup; - const params = { terminate_after: 1, apm: { diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_environments/index.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_environments/index.ts index 46ab82152caad..fb335fa231be1 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_environments/index.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/get_environments/index.ts @@ -10,15 +10,18 @@ import { getAllEnvironments } from '../../../environments/get_all_environments'; import { Setup } from '../../../../lib/helpers/setup_request'; import { getExistingEnvironmentsForService } from './get_existing_environments_for_service'; import { ALL_OPTION_VALUE } from '../../../../../common/agent_configuration/all_option'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getEnvironments({ serviceName, setup, + apmEventClient, searchAggregatedTransactions, size, }: { serviceName: string | undefined; setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; size: number; }) { @@ -27,7 +30,7 @@ export async function getEnvironments({ getAllEnvironments({ searchAggregatedTransactions, serviceName, - setup, + apmEventClient, size, }), getExistingEnvironmentsForService({ serviceName, setup, size }), diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/queries.test.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/queries.test.ts index 49a97c1ca4f77..59c52c37601cd 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/queries.test.ts @@ -24,11 +24,11 @@ describe('agent configuration queries', () => { describe('getAllEnvironments', () => { it('fetches all environments', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getAllEnvironments({ searchAggregatedTransactions: false, serviceName: 'foo', - setup, + apmEventClient, size: 50, }) ); diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts index eb04de4430381..77eb625c0b016 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts @@ -25,6 +25,7 @@ import { } from '../../../../common/agent_configuration/runtime_types/agent_configuration_intake_rt'; import { getSearchTransactionsEvents } from '../../../lib/helpers/transactions'; import { syncAgentConfigsToApmPackagePolicies } from '../../fleet/sync_agent_configs_to_apm_package_policies'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; // get list of configurations const agentConfigurationRoute = createApmServerRoute({ @@ -269,13 +270,16 @@ const listAgentConfigurationEnvironmentsRoute = createApmServerRoute({ ): Promise<{ environments: Array<{ name: string; alreadyConfigured: boolean }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { context, params } = resources; const coreContext = await context.core; const { serviceName, start, end } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery: '', start, @@ -287,6 +291,7 @@ const listAgentConfigurationEnvironmentsRoute = createApmServerRoute({ const environments = await getEnvironments({ serviceName, setup, + apmEventClient, searchAggregatedTransactions, size, }); @@ -303,10 +308,13 @@ const agentConfigurationAgentNameRoute = createApmServerRoute({ }), options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ agentName: string | undefined }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.query; - const agentName = await getAgentNameByService({ serviceName, setup }); + const agentName = await getAgentNameByService({ + serviceName, + apmEventClient, + }); return { agentName }; }, }); diff --git a/x-pack/plugins/apm/server/routes/settings/anomaly_detection/route.ts b/x-pack/plugins/apm/server/routes/settings/anomaly_detection/route.ts index e30f669b9cd7b..68b4ab7e55c03 100644 --- a/x-pack/plugins/apm/server/routes/settings/anomaly_detection/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/anomaly_detection/route.ts @@ -20,6 +20,7 @@ import { notifyFeatureUsage } from '../../../feature'; import { updateToV3 } from './update_to_v3'; import { environmentStringRt } from '../../../../common/environment_rt'; import { getMlJobsWithAPMGroup } from '../../../lib/anomaly_detection/get_ml_jobs_with_apm_group'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; // get ML anomaly detection jobs for each environment const anomalyDetectionJobsRoute = createApmServerRoute({ @@ -94,11 +95,14 @@ const anomalyDetectionEnvironmentsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/settings/anomaly-detection/environments', options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ environments: string[] }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const coreContext = await resources.context.core; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery: '', }); @@ -108,7 +112,7 @@ const anomalyDetectionEnvironmentsRoute = createApmServerRoute({ const environments = await getAllEnvironments({ includeMissing: true, searchAggregatedTransactions, - setup, + apmEventClient, size, }); diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.test.ts b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.test.ts index e6ba932ca58d6..afbe4c1d7bbe4 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.test.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.test.ts @@ -10,29 +10,29 @@ import { SearchParamsMock, } from '../../../utils/test_helpers'; import { getTransaction } from './get_transaction'; -import { Setup } from '../../../lib/helpers/setup_request'; import { SERVICE_NAME, TRANSACTION_TYPE, SERVICE_ENVIRONMENT, TRANSACTION_NAME, } from '../../../../common/elasticsearch_fieldnames'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; describe('custom link get transaction', () => { let mock: SearchParamsMock; it('fetches without filter', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTransaction({ - setup: setup as unknown as Setup, + apmEventClient: apmEventClient as unknown as APMEventClient, }) ); expect(mock.params).toMatchSnapshot(); }); it('fetches with all filter', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTransaction({ - setup: setup as unknown as Setup, + apmEventClient: apmEventClient as unknown as APMEventClient, filters: { [SERVICE_NAME]: 'foo', [SERVICE_ENVIRONMENT]: 'bar', diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts index 0dfece7bdc34b..d454b447b17f9 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts @@ -8,19 +8,17 @@ import * as t from 'io-ts'; import { compact } from 'lodash'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { Setup } from '../../../lib/helpers/setup_request'; import { filterOptionsRt } from './custom_link_types'; import { splitFilterValueByComma } from './helper'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransaction({ - setup, + apmEventClient, filters = {}, }: { - setup: Setup; + apmEventClient: APMEventClient; filters?: t.TypeOf; }) { - const { apmEventClient } = setup; - const esFilters = compact( Object.entries(filters) // loops through the filters splitting the value by comma and removing white spaces diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link/route.ts b/x-pack/plugins/apm/server/routes/settings/custom_link/route.ts index 1bd6328bdcee5..60d2642acfae3 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link/route.ts @@ -19,6 +19,7 @@ import { deleteCustomLink } from './delete_custom_link'; import { getTransaction } from './get_transaction'; import { listCustomLinks } from './list_custom_links'; import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; const customLinkTransactionRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/settings/custom_links/transaction', @@ -31,12 +32,12 @@ const customLinkTransactionRoute = createApmServerRoute({ ): Promise< import('./../../../../typings/es_schemas/ui/transaction').Transaction > => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { query } = params; // picks only the items listed in FILTER_OPTIONS const filters = pick(query, FILTER_OPTIONS); - return await getTransaction({ setup, filters }); + return await getTransaction({ apmEventClient, filters }); }, }); diff --git a/x-pack/plugins/apm/server/routes/span_links/get_linked_children.ts b/x-pack/plugins/apm/server/routes/span_links/get_linked_children.ts index 172463ff7cf64..60dfe40f469fb 100644 --- a/x-pack/plugins/apm/server/routes/span_links/get_linked_children.ts +++ b/x-pack/plugins/apm/server/routes/span_links/get_linked_children.ts @@ -18,24 +18,22 @@ import { } from '../../../common/elasticsearch_fieldnames'; import type { SpanRaw } from '../../../typings/es_schemas/raw/span_raw'; import type { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; -import { Setup } from '../../lib/helpers/setup_request'; import { getBufferedTimerange } from './utils'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; async function fetchLinkedChildrenOfSpan({ traceId, - setup, + apmEventClient, start, end, spanId, }: { traceId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; spanId?: string; }) { - const { apmEventClient } = setup; - const { startWithBuffer, endWithBuffer } = getBufferedTimerange({ start, end, @@ -83,18 +81,18 @@ function getSpanId(source: TransactionRaw | SpanRaw) { export async function getLinkedChildrenCountBySpanId({ traceId, - setup, + apmEventClient, start, end, }: { traceId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { const linkedChildren = await fetchLinkedChildrenOfSpan({ traceId, - setup, + apmEventClient, start, end, }); @@ -115,20 +113,20 @@ export async function getLinkedChildrenCountBySpanId({ export async function getLinkedChildrenOfSpan({ traceId, spanId, - setup, + apmEventClient, start, end, }: { traceId: string; spanId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { const linkedChildren = await fetchLinkedChildrenOfSpan({ traceId, spanId, - setup, + apmEventClient, start, end, }); diff --git a/x-pack/plugins/apm/server/routes/span_links/get_linked_parents.ts b/x-pack/plugins/apm/server/routes/span_links/get_linked_parents.ts index 3bc8d9ef59419..76efb549bc222 100644 --- a/x-pack/plugins/apm/server/routes/span_links/get_linked_parents.ts +++ b/x-pack/plugins/apm/server/routes/span_links/get_linked_parents.ts @@ -15,10 +15,10 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { SpanRaw } from '../../../typings/es_schemas/raw/span_raw'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getLinkedParentsOfSpan({ - setup, + apmEventClient, traceId, spanId, start, @@ -27,13 +27,11 @@ export async function getLinkedParentsOfSpan({ }: { traceId: string; spanId: string; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; processorEvent: ProcessorEvent; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search('get_linked_parents_of_span', { apm: { events: [processorEvent], diff --git a/x-pack/plugins/apm/server/routes/span_links/get_span_links_details.ts b/x-pack/plugins/apm/server/routes/span_links/get_span_links_details.ts index a09d10b422834..c27764e91fbcc 100644 --- a/x-pack/plugins/apm/server/routes/span_links/get_span_links_details.ts +++ b/x-pack/plugins/apm/server/routes/span_links/get_span_links_details.ts @@ -26,24 +26,22 @@ import { SpanLinkDetails } from '../../../common/span_links'; import { SpanLink } from '../../../typings/es_schemas/raw/fields/span_links'; import { SpanRaw } from '../../../typings/es_schemas/raw/span_raw'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; -import { Setup } from '../../lib/helpers/setup_request'; import { getBufferedTimerange } from './utils'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; async function fetchSpanLinksDetails({ - setup, + apmEventClient, kuery, spanLinks, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; kuery: string; spanLinks: SpanLink[]; start: number; end: number; }) { - const { apmEventClient } = setup; - const { startWithBuffer, endWithBuffer } = getBufferedTimerange({ start, end, @@ -119,13 +117,13 @@ async function fetchSpanLinksDetails({ } export async function getSpanLinksDetails({ - setup, + apmEventClient, spanLinks, kuery, start, end, }: { - setup: Setup; + apmEventClient: APMEventClient; spanLinks: SpanLink[]; kuery: string; start: number; @@ -140,7 +138,7 @@ export async function getSpanLinksDetails({ const chunkedResponses = await Promise.all( spanLinksChunks.map((spanLinksChunk) => fetchSpanLinksDetails({ - setup, + apmEventClient, kuery, spanLinks: spanLinksChunk, start, diff --git a/x-pack/plugins/apm/server/routes/span_links/route.ts b/x-pack/plugins/apm/server/routes/span_links/route.ts index 34b5864778144..18f361503d374 100644 --- a/x-pack/plugins/apm/server/routes/span_links/route.ts +++ b/x-pack/plugins/apm/server/routes/span_links/route.ts @@ -5,7 +5,6 @@ * 2.0. */ import * as t from 'io-ts'; -import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getSpanLinksDetails } from './get_span_links_details'; import { getLinkedChildrenOfSpan } from './get_linked_children'; @@ -13,6 +12,7 @@ import { kueryRt, rangeRt } from '../default_api_types'; import { SpanLinkDetails } from '../../../common/span_links'; import { processorEventRt } from '../../../common/processor_event'; import { getLinkedParentsOfSpan } from './get_linked_parents'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const linkedParentsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents', @@ -36,9 +36,9 @@ const linkedParentsRoute = createApmServerRoute({ const { params: { query, path }, } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const linkedParents = await getLinkedParentsOfSpan({ - setup, + apmEventClient, traceId: path.traceId, spanId: path.spanId, start: query.start, @@ -48,7 +48,7 @@ const linkedParentsRoute = createApmServerRoute({ return { spanLinksDetails: await getSpanLinksDetails({ - setup, + apmEventClient, spanLinks: linkedParents, kuery: query.kuery, start: query.start, @@ -76,9 +76,9 @@ const linkedChildrenRoute = createApmServerRoute({ const { params: { query, path }, } = resources; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const linkedChildren = await getLinkedChildrenOfSpan({ - setup, + apmEventClient, traceId: path.traceId, spanId: path.spanId, start: query.start, @@ -87,7 +87,7 @@ const linkedChildrenRoute = createApmServerRoute({ return { spanLinksDetails: await getSpanLinksDetails({ - setup, + apmEventClient, spanLinks: linkedChildren, kuery: query.kuery, start: query.start, diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/get_service_statistics.ts b/x-pack/plugins/apm/server/routes/storage_explorer/get_service_statistics.ts index 169bff0cd7113..95a74d13c1313 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/get_service_statistics.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/get_service_statistics.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { termQuery, kqlQuery, @@ -34,9 +33,11 @@ import { getEstimatedSizeForDocumentsInIndex, } from './indices_stats_helpers'; import { RandomSampler } from '../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; async function getMainServiceStatistics({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -46,6 +47,7 @@ async function getMainServiceStatistics({ kuery, }: { setup: Setup; + apmEventClient: APMEventClient; context: ApmPluginRequestHandlerContext; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; randomSampler: RandomSampler; @@ -54,8 +56,6 @@ async function getMainServiceStatistics({ environment: string; kuery: string; }) { - const { apmEventClient } = setup; - const [{ indices: allIndicesStats }, response] = await Promise.all([ getTotalIndicesStats({ context, setup }), apmEventClient.search('get_main_service_statistics', { @@ -82,7 +82,7 @@ async function getMainServiceStatistics({ indexLifeCyclePhaseToDataTier[indexLifecyclePhase] ) : []), - ] as QueryDslQueryContainer[], + ], }, }, aggs: { @@ -177,6 +177,7 @@ async function getMainServiceStatistics({ export async function getServiceStatistics({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -187,6 +188,7 @@ export async function getServiceStatistics({ searchAggregatedTransactions, }: { setup: Setup; + apmEventClient: APMEventClient; context: ApmPluginRequestHandlerContext; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; randomSampler: RandomSampler; @@ -200,6 +202,7 @@ export async function getServiceStatistics({ await Promise.all([ getMainServiceStatistics({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -209,7 +212,7 @@ export async function getServiceStatistics({ end, }), getTotalTransactionsPerService({ - setup, + apmEventClient, searchAggregatedTransactions, indexLifecyclePhase, randomSampler, diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/get_size_timeseries.ts b/x-pack/plugins/apm/server/routes/storage_explorer/get_size_timeseries.ts index f513efe059f71..2337243a64123 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/get_size_timeseries.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/get_size_timeseries.ts @@ -29,11 +29,13 @@ import { getTotalIndicesStats, getEstimatedSizeForDocumentsInIndex, } from './indices_stats_helpers'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getSizeTimeseries({ environment, kuery, setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -44,6 +46,7 @@ export async function getSizeTimeseries({ environment: string; kuery: string; setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; @@ -51,8 +54,6 @@ export async function getSizeTimeseries({ randomSampler: RandomSampler; context: ApmPluginRequestHandlerContext; }) { - const { apmEventClient } = setup; - const { intervalString } = getBucketSizeForAggregatedTransactions({ start, end, diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_processor_event.ts b/x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_service.ts similarity index 55% rename from x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_processor_event.ts rename to x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_service.ts index 8f92ce9d93809..ae6b0a82ca0e7 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_processor_event.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/get_storage_details_per_service.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { termQuery, kqlQuery, @@ -28,11 +27,15 @@ import { ApmPluginRequestHandlerContext } from '../typings'; import { getTotalIndicesStats, getEstimatedSizeForDocumentsInIndex, + getIndicesLifecycleStatus, + getIndicesInfo, } from './indices_stats_helpers'; import { RandomSampler } from '../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getStorageDetailsPerProcessorEvent({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -43,6 +46,7 @@ export async function getStorageDetailsPerProcessorEvent({ serviceName, }: { setup: Setup; + apmEventClient: APMEventClient; context: ApmPluginRequestHandlerContext; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; randomSampler: RandomSampler; @@ -52,11 +56,9 @@ export async function getStorageDetailsPerProcessorEvent({ kuery: string; serviceName: string; }) { - const { apmEventClient } = setup; - const [{ indices: allIndicesStats }, response] = await Promise.all([ getTotalIndicesStats({ setup, context }), - apmEventClient.search('get_storage_details_per_processor_event', { + apmEventClient.search('get_storage_details_per_service', { apm: { events: [ ProcessorEvent.span, @@ -81,7 +83,7 @@ export async function getStorageDetailsPerProcessorEvent({ indexLifeCyclePhaseToDataTier[indexLifecyclePhase] ) : []), - ] as QueryDslQueryContainer[], + ], }, }, aggs: { @@ -153,3 +155,122 @@ export async function getStorageDetailsPerProcessorEvent({ }; }); } + +export async function getStorageDetailsPerIndex({ + apmEventClient, + setup, + context, + indexLifecyclePhase, + randomSampler, + start, + end, + environment, + kuery, + serviceName, +}: { + apmEventClient: APMEventClient; + setup: Setup; + context: ApmPluginRequestHandlerContext; + indexLifecyclePhase: IndexLifecyclePhaseSelectOption; + randomSampler: RandomSampler; + start: number; + end: number; + environment: string; + kuery: string; + serviceName: string; +}) { + const [ + { indices: allIndicesStats }, + indicesLifecycleStatus, + indicesInfo, + response, + ] = await Promise.all([ + getTotalIndicesStats({ setup, context }), + getIndicesLifecycleStatus({ setup, context }), + getIndicesInfo({ setup, context }), + apmEventClient.search('get_storage_details_per_index', { + apm: { + events: [ + ProcessorEvent.span, + ProcessorEvent.transaction, + ProcessorEvent.error, + ProcessorEvent.metric, + ], + }, + body: { + size: 0, + track_total_hits: false, + query: { + bool: { + filter: [ + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...rangeQuery(start, end), + ...termQuery(SERVICE_NAME, serviceName), + ...(indexLifecyclePhase !== IndexLifecyclePhaseSelectOption.All + ? termQuery( + TIER, + indexLifeCyclePhaseToDataTier[indexLifecyclePhase] + ) + : []), + ], + }, + }, + aggs: { + sample: { + random_sampler: randomSampler, + aggs: { + indices: { + terms: { + field: INDEX, + size: 500, + }, + aggs: { + number_of_metric_docs_for_index: { + value_count: { + field: INDEX, + }, + }, + }, + }, + }, + }, + }, + }, + }), + ]); + + return ( + response.aggregations?.sample.indices.buckets.map((bucket) => { + const indexName = bucket.key as string; + const numberOfDocs = bucket.number_of_metric_docs_for_index.value; + const indexInfo = indicesInfo[indexName]; + const indexLifecycle = indicesLifecycleStatus[indexName]; + + const size = + allIndicesStats && + getEstimatedSizeForDocumentsInIndex({ + allIndicesStats, + indexName, + numberOfDocs, + }); + + return { + indexName, + numberOfDocs, + primary: indexInfo + ? indexInfo.settings?.index?.number_of_shards ?? 0 + : undefined, + replica: indexInfo + ? indexInfo.settings?.number_of_replicas ?? 0 + : undefined, + size, + dataStream: indexInfo?.data_stream, + lifecyclePhase: + indexLifecycle && 'phase' in indexLifecycle + ? indexLifecycle.phase + : undefined, + }; + }) ?? [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/get_summary_statistics.ts b/x-pack/plugins/apm/server/routes/storage_explorer/get_summary_statistics.ts index dfa510e8f0890..2bb471751385c 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/get_summary_statistics.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/get_summary_statistics.ts @@ -6,7 +6,6 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { termQuery, kqlQuery, @@ -15,6 +14,7 @@ import { import { getTotalIndicesStats, getEstimatedSizeForDocumentsInIndex, + getApmDiskSpacedUsedPct, } from './indices_stats_helpers'; import { Setup } from '../../lib/helpers/setup_request'; import { ApmPluginRequestHandlerContext } from '../typings'; @@ -36,9 +36,10 @@ import { isRootTransaction, } from '../../lib/helpers/transactions'; import { calculateThroughputWithRange } from '../../lib/helpers/calculate_throughput'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTracesPerMinute({ - setup, + apmEventClient, indexLifecyclePhase, start, end, @@ -46,7 +47,7 @@ export async function getTracesPerMinute({ kuery, searchAggregatedTransactions, }: { - setup: Setup; + apmEventClient: APMEventClient; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; start: number; end: number; @@ -54,8 +55,6 @@ export async function getTracesPerMinute({ kuery: string; searchAggregatedTransactions: boolean; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search('get_traces_per_minute', { apm: { events: [getProcessorEventForTransactions(searchAggregatedTransactions)], @@ -103,6 +102,7 @@ export async function getTracesPerMinute({ export async function getMainSummaryStats({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -112,6 +112,7 @@ export async function getMainSummaryStats({ kuery, }: { setup: Setup; + apmEventClient: APMEventClient; context: ApmPluginRequestHandlerContext; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; randomSampler: RandomSampler; @@ -120,10 +121,9 @@ export async function getMainSummaryStats({ environment: string; kuery: string; }) { - const { apmEventClient } = setup; - - const [{ indices: allIndicesStats }, res] = await Promise.all([ + const [totalIndicesStats, totalDiskSpace, res] = await Promise.all([ getTotalIndicesStats({ context, setup }), + getApmDiskSpacedUsedPct(context), apmEventClient.search('get_storage_explorer_main_summary_stats', { apm: { events: [ @@ -148,7 +148,7 @@ export async function getMainSummaryStats({ indexLifeCyclePhaseToDataTier[indexLifecyclePhase] ) : []), - ] as QueryDslQueryContainer[], + ], }, }, aggs: { @@ -180,7 +180,8 @@ export async function getMainSummaryStats({ }), ]); - const estimatedSize = allIndicesStats + const { indices: allIndicesStats } = totalIndicesStats; + const estimatedIncrementalSize = allIndicesStats ? res.aggregations?.sample.indices.buckets.reduce((prev, curr) => { return ( prev + @@ -194,10 +195,13 @@ export async function getMainSummaryStats({ : 0; const durationAsDays = (end - start) / 1000 / 60 / 60 / 24; + const totalApmSize = totalIndicesStats._all.total?.store?.size_in_bytes ?? 0; return { + totalSize: totalApmSize, + diskSpaceUsedPct: totalApmSize / totalDiskSpace, numberOfServices: res.aggregations?.services_count.value ?? 0, - estimatedSize, - dailyDataGeneration: estimatedSize / durationAsDays, + estimatedIncrementalSize, + dailyDataGeneration: estimatedIncrementalSize / durationAsDays, }; } diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/get_total_transactions_per_service.ts b/x-pack/plugins/apm/server/routes/storage_explorer/get_total_transactions_per_service.ts index 793c69ab71b4c..1f883adee3f70 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/get_total_transactions_per_service.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/get_total_transactions_per_service.ts @@ -4,13 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { termQuery, kqlQuery, rangeQuery, } from '@kbn/observability-plugin/server'; -import { Setup } from '../../lib/helpers/setup_request'; import { getProcessorEventForTransactions, getDocumentTypeFilterForTransactions, @@ -22,9 +20,10 @@ import { } from '../../../common/storage_explorer_types'; import { environmentQuery } from '../../../common/utils/environment_query'; import { RandomSampler } from '../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTotalTransactionsPerService({ - setup, + apmEventClient, searchAggregatedTransactions, indexLifecyclePhase, randomSampler, @@ -33,7 +32,7 @@ export async function getTotalTransactionsPerService({ environment, kuery, }: { - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; indexLifecyclePhase: IndexLifecyclePhaseSelectOption; randomSampler: RandomSampler; @@ -42,8 +41,6 @@ export async function getTotalTransactionsPerService({ environment: string; kuery: string; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_total_transactions_per_service', { @@ -70,7 +67,7 @@ export async function getTotalTransactionsPerService({ indexLifeCyclePhaseToDataTier[indexLifecyclePhase] ) : []), - ] as QueryDslQueryContainer[], + ], }, }, aggs: { diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/has_storage_explorer_privileges.ts b/x-pack/plugins/apm/server/routes/storage_explorer/has_storage_explorer_privileges.ts index 714c0eee1c62c..e69c3f33f8d9d 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/has_storage_explorer_privileges.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/has_storage_explorer_privileges.ts @@ -28,17 +28,19 @@ export async function hasStorageExplorerPrivileges({ ); const esClient = (await context.core).elasticsearch.client; - const { index } = await esClient.asCurrentUser.security.hasPrivileges({ - body: { - index: [ - { - names, - privileges: ['monitor'], - }, - ], - }, - }); + const { index, cluster } = + await esClient.asCurrentUser.security.hasPrivileges({ + body: { + index: [ + { + names, + privileges: ['monitor'], + }, + ], + cluster: ['monitor'], + }, + }); - const hasPrivileges = every(index, 'monitor'); + const hasPrivileges = cluster.monitor && every(index, 'monitor'); return hasPrivileges; } diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/indices_stats_helpers.ts b/x-pack/plugins/apm/server/routes/storage_explorer/indices_stats_helpers.ts index aa9e854cc4a29..d7ce952b2fd50 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/indices_stats_helpers.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/indices_stats_helpers.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { uniq } from 'lodash'; +import { uniq, values, sumBy } from 'lodash'; import { IndicesStatsIndicesStats } from '@elastic/elasticsearch/lib/api/types'; import { Setup } from '../../lib/helpers/setup_request'; import { ApmPluginRequestHandlerContext } from '../typings'; @@ -16,10 +16,7 @@ export async function getTotalIndicesStats({ context: ApmPluginRequestHandlerContext; setup: Setup; }) { - const { - indices: { transaction, span, metric, error }, - } = setup; - const index = uniq([transaction, span, metric, error]).join(); + const index = getApmIndicesCombined(setup); const esClient = (await context.core).elasticsearch.client; const totalStats = await esClient.asCurrentUser.indices.stats({ index }); return totalStats; @@ -44,3 +41,67 @@ export function getEstimatedSizeForDocumentsInIndex({ return estimatedSize; } + +export async function getApmDiskSpacedUsedPct( + context: ApmPluginRequestHandlerContext +) { + const esClient = (await context.core).elasticsearch.client; + const { nodes: diskSpacePerNode } = await esClient.asCurrentUser.nodes.stats({ + metric: 'fs', + filter_path: 'nodes.*.fs.total.total_in_bytes', + }); + + const totalDiskSpace = sumBy( + values(diskSpacePerNode), + (node) => node?.fs?.total?.total_in_bytes ?? 0 + ); + + return totalDiskSpace; +} + +export async function getIndicesLifecycleStatus({ + context, + setup, +}: { + context: ApmPluginRequestHandlerContext; + setup: Setup; +}) { + const index = getApmIndicesCombined(setup); + const esClient = (await context.core).elasticsearch.client; + const { indices } = await esClient.asCurrentUser.ilm.explainLifecycle({ + index, + filter_path: 'indices.*.phase', + }); + + return indices; +} + +export async function getIndicesInfo({ + context, + setup, +}: { + context: ApmPluginRequestHandlerContext; + setup: Setup; +}) { + const index = getApmIndicesCombined(setup); + const esClient = (await context.core).elasticsearch.client; + const indicesInfo = await esClient.asCurrentUser.indices.get({ + index, + filter_path: [ + '*.settings.index.number_of_shards', + '*.settings.index.number_of_replicas', + '*.data_stream', + ], + features: ['settings'], + }); + + return indicesInfo; +} + +export function getApmIndicesCombined(setup: Setup) { + const { + indices: { transaction, span, metric, error }, + } = setup; + + return uniq([transaction, span, metric, error]).join(); +} diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.test.ts b/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.test.ts new file mode 100644 index 0000000000000..d24ef35158170 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.test.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Setup } from '../../lib/helpers/setup_request'; +import { isCrossClusterSearch } from './is_cross_cluster_search'; +import { ApmIndicesConfig } from '@kbn/observability-plugin/common/typings'; + +describe('isCrossClusterSearch', () => { + it('returns false when there are no remote clusters in APM indices', () => { + const mockedSetup = { + indices: { + transaction: 'traces-apm*', + span: 'traces-apm*', + metric: 'metrics-apm*', + error: 'logs-apm*', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(false); + }); + + it('returns false when there are multiple indices per type and no remote clusters in APM indices', () => { + const mockedSetup = { + indices: { + transaction: 'traces-apm*,test-apm*', + span: 'traces-apm*,test-apm*', + metric: 'metrics-apm*,test-apm*', + error: 'logs-apm*,test-apm*', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(false); + }); + + it('returns false when there are remote clusters in onboarding and sourcemap indices', () => { + const mockedSetup = { + indices: { + transaction: '', + span: '', + metric: '', + error: '', + onboarding: 'apm-*,remote_cluster:apm-*', + sourcemap: 'apm-*,remote_cluster:apm-*', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(false); + }); + + it('returns true when there are remote clusters in transaction indices', () => { + const mockedSetup = { + indices: { + transaction: 'traces-apm*,remote_cluster:traces-apm*', + span: '', + metric: '', + error: '', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(true); + }); + + it('returns true when there are remote clusters in span indices', () => { + const mockedSetup = { + indices: { + transaction: '', + span: 'traces-apm*,remote_cluster:traces-apm*', + metric: '', + error: '', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(true); + }); + + it('returns true when there are remote clusters in metrics indices', () => { + const mockedSetup = { + indices: { + transaction: '', + span: '', + metric: 'metrics-apm*,remote_cluster:metrics-apm*', + error: '', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(true); + }); + + it('returns true when there are remote clusters in error indices', () => { + const mockedSetup = { + indices: { + transaction: '', + span: '', + metric: '', + error: 'logs-apm*,remote_cluster:logs-apm*', + } as ApmIndicesConfig, + } as unknown as Setup; + + expect(isCrossClusterSearch(mockedSetup)).toBe(true); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.ts b/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.ts new file mode 100644 index 0000000000000..fbbe7a1347931 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/storage_explorer/is_cross_cluster_search.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Setup } from '../../lib/helpers/setup_request'; +import { getApmIndicesCombined } from './indices_stats_helpers'; + +export function isCrossClusterSearch(setup: Setup) { + // Check if a remote cluster is set in APM indices + return getApmIndicesCombined(setup).includes(':'); +} diff --git a/x-pack/plugins/apm/server/routes/storage_explorer/route.ts b/x-pack/plugins/apm/server/routes/storage_explorer/route.ts index 9d817efbf34f5..6872bdd22a09d 100644 --- a/x-pack/plugins/apm/server/routes/storage_explorer/route.ts +++ b/x-pack/plugins/apm/server/routes/storage_explorer/route.ts @@ -9,10 +9,14 @@ import * as t from 'io-ts'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; +import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getSearchTransactionsEvents } from '../../lib/helpers/transactions'; import { setupRequest } from '../../lib/helpers/setup_request'; -import { indexLifecyclePhaseRt } from '../../../common/storage_explorer_types'; +import { + indexLifecyclePhaseRt, + IndexLifecyclePhaseSelectOption, +} from '../../../common/storage_explorer_types'; import { getServiceStatistics } from './get_service_statistics'; import { probabilityRt, @@ -21,7 +25,10 @@ import { rangeRt, } from '../default_api_types'; import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; -import { getStorageDetailsPerProcessorEvent } from './get_storage_details_per_processor_event'; +import { + getStorageDetailsPerIndex, + getStorageDetailsPerProcessorEvent, +} from './get_storage_details_per_service'; import { getRandomSampler } from '../../lib/helpers/get_random_sampler'; import { getSizeTimeseries } from './get_size_timeseries'; import { hasStorageExplorerPrivileges } from './has_storage_explorer_privileges'; @@ -29,6 +36,9 @@ import { getMainSummaryStats, getTracesPerMinute, } from './get_summary_statistics'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; +import { isCrossClusterSearch } from './is_cross_cluster_search'; +import { getServiceNamesFromTermsEnum } from '../services/get_services/get_sorted_and_filtered_services'; const storageExplorerRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/storage_explorer', @@ -71,19 +81,21 @@ const storageExplorerRoute = createApmServerRoute({ }, } = params; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery, }); const serviceStatistics = await getServiceStatistics({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -127,6 +139,15 @@ const storageExplorerServiceDetailsRoute = createApmServerRoute({ docs: number; size: number; }>; + indicesStats: Array<{ + indexName: string; + numberOfDocs: number; + primary?: number | string; + replica?: number | string; + size?: number; + dataStream?: string; + lifecyclePhase?: string; + }>; }> => { const { params, @@ -147,24 +168,40 @@ const storageExplorerServiceDetailsRoute = createApmServerRoute({ }, } = params; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); - const processorEventStats = await getStorageDetailsPerProcessorEvent({ - setup, - context, - indexLifecyclePhase, - randomSampler, - environment, - kuery, - start, - end, - serviceName, - }); + const [processorEventStats, indicesStats] = await Promise.all([ + getStorageDetailsPerProcessorEvent({ + apmEventClient, + setup, + context, + indexLifecyclePhase, + randomSampler, + environment, + kuery, + start, + end, + serviceName, + }), + getStorageDetailsPerIndex({ + apmEventClient, + setup, + context, + indexLifecyclePhase, + randomSampler, + environment, + kuery, + start, + end, + serviceName, + }), + ]); - return { processorEventStats }; + return { processorEventStats, indicesStats }; }, }); @@ -206,13 +243,14 @@ const storageChartRoute = createApmServerRoute({ }, } = params; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery, }); @@ -226,6 +264,7 @@ const storageChartRoute = createApmServerRoute({ start, end, setup, + apmEventClient, context, }); @@ -274,7 +313,9 @@ const storageExplorerSummaryStatsRoute = createApmServerRoute({ ): Promise<{ tracesPerMinute: number; numberOfServices: number; - estimatedSize: number; + totalSize: number; + diskSpaceUsedPct: number; + estimatedIncrementalSize: number; dailyDataGeneration: number; }> => { const { @@ -295,13 +336,14 @@ const storageExplorerSummaryStatsRoute = createApmServerRoute({ }, } = params; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery, }); @@ -309,6 +351,7 @@ const storageExplorerSummaryStatsRoute = createApmServerRoute({ const [mainSummaryStats, tracesPerMinute] = await Promise.all([ getMainSummaryStats({ setup, + apmEventClient, context, indexLifecyclePhase, randomSampler, @@ -318,7 +361,7 @@ const storageExplorerSummaryStatsRoute = createApmServerRoute({ kuery, }), getTracesPerMinute({ - setup, + apmEventClient, indexLifecyclePhase, start, end, @@ -335,12 +378,68 @@ const storageExplorerSummaryStatsRoute = createApmServerRoute({ }, }); +const storageExplorerIsCrossClusterSearchRoute = createApmServerRoute({ + endpoint: 'GET /internal/apm/storage_explorer/is_cross_cluster_search', + options: { tags: ['access:apm'] }, + handler: async (resources): Promise<{ isCrossClusterSearch: boolean }> => { + const setup = await setupRequest(resources); + return { isCrossClusterSearch: isCrossClusterSearch(setup) }; + }, +}); + +const storageExplorerGetServices = createApmServerRoute({ + endpoint: 'GET /internal/apm/storage_explorer/get_services', + options: { + tags: ['access:apm'], + }, + params: t.type({ + query: t.intersection([indexLifecyclePhaseRt, environmentRt, kueryRt]), + }), + handler: async ( + resources + ): Promise<{ + services: Array<{ + serviceName: string; + }>; + }> => { + const { + query: { environment, kuery, indexLifecyclePhase }, + } = resources.params; + + if ( + kuery || + indexLifecyclePhase !== IndexLifecyclePhaseSelectOption.All || + environment !== ENVIRONMENT_ALL.value + ) { + return { + services: [], + }; + } + + const apmEventClient = await getApmEventClient(resources); + + const services = await getServiceNamesFromTermsEnum({ + apmEventClient, + environment, + maxNumberOfServices: 500, + }); + + return { + services: services.map((serviceName): { serviceName: string } => ({ + serviceName, + })), + }; + }, +}); + export const storageExplorerRouteRepository = { ...storageExplorerRoute, ...storageExplorerServiceDetailsRoute, ...storageChartRoute, ...storageExplorerPrivilegesRoute, ...storageExplorerSummaryStatsRoute, + ...storageExplorerIsCrossClusterSearchRoute, + ...storageExplorerGetServices, }; const SECURITY_REQUIRED_MESSAGE = i18n.translate( diff --git a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts index 56ed34805c2fb..856b6bea1b9a5 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts @@ -8,14 +8,14 @@ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getSuggestionsWithTermsAggregation({ fieldName, fieldValue, searchAggregatedTransactions, serviceName, - setup, + apmEventClient, size, start, end, @@ -24,13 +24,11 @@ export async function getSuggestionsWithTermsAggregation({ fieldValue: string; searchAggregatedTransactions: boolean; serviceName?: string; - setup: Setup; + apmEventClient: APMEventClient; size: number; start: number; end: number; }) { - const { apmEventClient } = setup; - const response = await apmEventClient.search( 'get_suggestions_with_terms_aggregation', { diff --git a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts index 4437a36151895..c945438ff01cf 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts @@ -6,13 +6,13 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; -import { Setup } from '../../lib/helpers/setup_request'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getSuggestionsWithTermsEnum({ fieldName, fieldValue, searchAggregatedTransactions, - setup, + apmEventClient, size, start, end, @@ -20,40 +20,35 @@ export async function getSuggestionsWithTermsEnum({ fieldName: string; fieldValue: string; searchAggregatedTransactions: boolean; - setup: Setup; + apmEventClient: APMEventClient; size: number; start: number; end: number; }) { - const { apmEventClient } = setup; - - const response = await apmEventClient.termsEnum( - 'get_suggestions_with_terms_enum', - { - apm: { - events: [ - getProcessorEventForTransactions(searchAggregatedTransactions), - ProcessorEvent.error, - ProcessorEvent.metric, - ], - }, - body: { - case_insensitive: true, - field: fieldName, - size, - string: fieldValue, - index_filter: { - range: { - ['@timestamp']: { - gte: start, - lte: end, - format: 'epoch_millis', - }, + const response = await apmEventClient.termsEnum('get_suggestions', { + apm: { + events: [ + getProcessorEventForTransactions(searchAggregatedTransactions), + ProcessorEvent.error, + ProcessorEvent.metric, + ], + }, + body: { + case_insensitive: true, + field: fieldName, + size, + string: fieldValue, + index_filter: { + range: { + ['@timestamp']: { + gte: start, + lte: end, + format: 'epoch_millis', }, }, }, - } - ); + }, + }); return { terms: response.terms }; } diff --git a/x-pack/plugins/apm/server/routes/suggestions/route.ts b/x-pack/plugins/apm/server/routes/suggestions/route.ts index f0396ac62ca51..976779816f960 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/route.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/route.ts @@ -13,6 +13,7 @@ import { getSearchTransactionsEvents } from '../../lib/helpers/transactions'; import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { rangeRt } from '../default_api_types'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const suggestionsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/suggestions', @@ -28,11 +29,14 @@ const suggestionsRoute = createApmServerRoute({ }), options: { tags: ['access:apm'] }, handler: async (resources): Promise<{ terms: string[] }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { context, params } = resources; const { fieldName, fieldValue, serviceName, start, end } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - apmEventClient: setup.apmEventClient, + apmEventClient, config: setup.config, kuery: '', }); @@ -46,7 +50,7 @@ const suggestionsRoute = createApmServerRoute({ fieldName, fieldValue, searchAggregatedTransactions, - setup, + apmEventClient, size, start, end, @@ -65,7 +69,7 @@ const suggestionsRoute = createApmServerRoute({ fieldValue, searchAggregatedTransactions, serviceName, - setup, + apmEventClient, size, start, end, diff --git a/x-pack/plugins/apm/server/routes/time_range_metadata/route.ts b/x-pack/plugins/apm/server/routes/time_range_metadata/route.ts index f0321f4cfde4d..bde0058b57560 100644 --- a/x-pack/plugins/apm/server/routes/time_range_metadata/route.ts +++ b/x-pack/plugins/apm/server/routes/time_range_metadata/route.ts @@ -7,7 +7,7 @@ import { toBooleanRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { TimeRangeMetadata } from '../../../common/time_range_metadata'; -import { setupRequest } from '../../lib/helpers/setup_request'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { getIsUsingServiceDestinationMetrics } from '../../lib/helpers/spans/get_is_using_service_destination_metrics'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { kueryRt, rangeRt } from '../default_api_types'; @@ -25,7 +25,7 @@ export const timeRangeMetadataRoute = createApmServerRoute({ tags: ['access:apm'], }, handler: async (resources): Promise => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { query: { useSpanName, start, end, kuery }, @@ -33,7 +33,7 @@ export const timeRangeMetadataRoute = createApmServerRoute({ const [isUsingServiceDestinationMetrics] = await Promise.all([ getIsUsingServiceDestinationMetrics({ - setup, + apmEventClient, useSpanName, start, end, diff --git a/x-pack/plugins/apm/server/routes/traces/get_top_traces_primary_stats.ts b/x-pack/plugins/apm/server/routes/traces/get_top_traces_primary_stats.ts index 92ff9c38260df..dc9143685902b 100644 --- a/x-pack/plugins/apm/server/routes/traces/get_top_traces_primary_stats.ts +++ b/x-pack/plugins/apm/server/routes/traces/get_top_traces_primary_stats.ts @@ -13,7 +13,6 @@ import { } from '@kbn/observability-plugin/server'; import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; import { withApmSpan } from '../../utils/with_apm_span'; -import { Setup } from '../../lib/helpers/setup_request'; import { asMutableArray } from '../../../common/utils/as_mutable_array'; import { environmentQuery } from '../../../common/utils/environment_query'; import { calculateImpactBuilder } from './calculate_impact_builder'; @@ -31,6 +30,7 @@ import { TRANSACTION_NAME, } from '../../../common/elasticsearch_fieldnames'; import { RandomSampler } from '../../lib/helpers/get_random_sampler'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export type BucketKey = Record< typeof TRANSACTION_NAME | typeof SERVICE_NAME, @@ -44,7 +44,7 @@ interface TopTracesParams { searchAggregatedTransactions: boolean; start: number; end: number; - setup: Setup; + apmEventClient: APMEventClient; randomSampler: RandomSampler; } export async function getTopTracesPrimaryStats({ @@ -54,11 +54,11 @@ export async function getTopTracesPrimaryStats({ searchAggregatedTransactions, start, end, - setup, + apmEventClient, randomSampler, }: TopTracesParams) { return withApmSpan('get_top_traces_primary_stats', async () => { - const response = await setup.apmEventClient.search( + const response = await apmEventClient.search( 'get_transaction_group_stats', { apm: { diff --git a/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts b/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts index f1c1efc8664ce..960924e1aa4b0 100644 --- a/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts @@ -18,16 +18,17 @@ import { TRACE_ID, TRANSACTION_DURATION, } from '../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../lib/helpers/setup_request'; import { getLinkedChildrenCountBySpanId } from '../span_links/get_linked_children'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import { APMConfig } from '../..'; export async function getTraceItems( traceId: string, - setup: Setup, + config: APMConfig, + apmEventClient: APMEventClient, start: number, end: number ) { - const { apmEventClient, config } = setup; const maxTraceItems = config.ui.maxTraceItems; const excludedLogLevels = ['debug', 'info', 'warning']; @@ -80,7 +81,7 @@ export async function getTraceItems( await Promise.all([ errorResponsePromise, traceResponsePromise, - getLinkedChildrenCountBySpanId({ traceId, setup, start, end }), + getLinkedChildrenCountBySpanId({ traceId, apmEventClient, start, end }), ]); const exceedsMax = traceResponse.hits.total.value > maxTraceItems; diff --git a/x-pack/plugins/apm/server/routes/traces/get_trace_samples_by_query.ts b/x-pack/plugins/apm/server/routes/traces/get_trace_samples_by_query.ts index 5f56d20dbbf9f..2e74d104592d7 100644 --- a/x-pack/plugins/apm/server/routes/traces/get_trace_samples_by_query.ts +++ b/x-pack/plugins/apm/server/routes/traces/get_trace_samples_by_query.ts @@ -11,7 +11,6 @@ import { } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { Environment } from '../../../common/environment_rt'; -import { Setup } from '../../lib/helpers/setup_request'; import { TraceSearchType } from '../../../common/trace_explorer'; import { environmentQuery } from '../../../common/utils/environment_query'; import { @@ -22,16 +21,17 @@ import { TRANSACTION_SAMPLED, } from '../../../common/elasticsearch_fieldnames'; import { asMutableArray } from '../../../common/utils/as_mutable_array'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTraceSamplesByQuery({ - setup, + apmEventClient, start, end, environment, query, type, }: { - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; environment: Environment; @@ -45,7 +45,7 @@ export async function getTraceSamplesByQuery({ if (type === TraceSearchType.kql) { traceIds = ( - await setup.apmEventClient.search('get_trace_ids_by_kql_query', { + await apmEventClient.search('get_trace_ids_by_kql_query', { apm: { events: [ ProcessorEvent.transaction, @@ -81,7 +81,7 @@ export async function getTraceSamplesByQuery({ } else if (type === TraceSearchType.eql) { traceIds = ( - await setup.apmEventClient.eqlSearch('get_trace_ids_by_eql_query', { + await apmEventClient.eqlSearch('get_trace_ids_by_eql_query', { apm: { events: [ ProcessorEvent.transaction, @@ -115,7 +115,7 @@ export async function getTraceSamplesByQuery({ return []; } - const traceSamplesResponse = await setup.apmEventClient.search( + const traceSamplesResponse = await apmEventClient.search( 'get_trace_samples_by_trace_ids', { apm: { diff --git a/x-pack/plugins/apm/server/routes/traces/queries.test.ts b/x-pack/plugins/apm/server/routes/traces/queries.test.ts index f1bd97fd88ebd..64e08d11acc74 100644 --- a/x-pack/plugins/apm/server/routes/traces/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/traces/queries.test.ts @@ -19,8 +19,8 @@ describe('trace queries', () => { }); it('fetches a trace', async () => { - mock = await inspectSearchParams((setup) => - getTraceItems('foo', setup, 0, 50000) + mock = await inspectSearchParams((setup, apmEventClient) => + getTraceItems('foo', setup.config, apmEventClient, 0, 50000) ); expect(mock.params).toMatchSnapshot(); diff --git a/x-pack/plugins/apm/server/routes/traces/route.ts b/x-pack/plugins/apm/server/routes/traces/route.ts index 336e862bcd09d..dc1408f9bddef 100644 --- a/x-pack/plugins/apm/server/routes/traces/route.ts +++ b/x-pack/plugins/apm/server/routes/traces/route.ts @@ -22,6 +22,7 @@ import { getTopTracesPrimaryStats } from './get_top_traces_primary_stats'; import { getTraceItems } from './get_trace_items'; import { getTraceSamplesByQuery } from './get_trace_samples_by_query'; import { getRandomSampler } from '../../lib/helpers/get_random_sampler'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const tracesRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/traces', @@ -51,13 +52,15 @@ const tracesRoute = createApmServerRoute({ const { environment, kuery, start, end, probability } = params.query; - const [setup, randomSampler] = await Promise.all([ + const [setup, apmEventClient, randomSampler] = await Promise.all([ setupRequest(resources), + getApmEventClient(resources), getRandomSampler({ security, request, probability }), ]); const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + apmEventClient, + config: setup.config, kuery, start, end, @@ -66,7 +69,7 @@ const tracesRoute = createApmServerRoute({ return await getTopTracesPrimaryStats({ environment, kuery, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -97,12 +100,15 @@ const tracesByIdRoute = createApmServerRoute({ >; linkedChildrenOfSpanCountBySpanId: Record; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { traceId } = params.path; const { start, end } = params.query; - - return getTraceItems(traceId, setup, start, end); + const { config } = setup; + return getTraceItems(traceId, config, apmEventClient, start, end); }, }); @@ -121,8 +127,8 @@ const rootTransactionByTraceIdRoute = createApmServerRoute({ }> => { const { params } = resources; const { traceId } = params.path; - const setup = await setupRequest(resources); - return getRootTransactionByTraceId(traceId, setup); + const apmEventClient = await getApmEventClient(resources); + return getRootTransactionByTraceId(traceId, apmEventClient); }, }); @@ -141,9 +147,9 @@ const transactionByIdRoute = createApmServerRoute({ }> => { const { params } = resources; const { transactionId } = params.path; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); return { - transaction: await getTransaction({ transactionId, setup }), + transaction: await getTransaction({ transactionId, apmEventClient }), }; }, }); @@ -173,11 +179,11 @@ const findTracesRoute = createApmServerRoute({ }> => { const { start, end, environment, query, type } = resources.params.query; - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); return { traceSamples: await getTraceSamplesByQuery({ - setup, + apmEventClient, start, end, environment, diff --git a/x-pack/plugins/apm/server/routes/transactions/breakdown/index.test.ts b/x-pack/plugins/apm/server/routes/transactions/breakdown/index.test.ts index 2df04fcdb0548..96487f7a6be72 100644 --- a/x-pack/plugins/apm/server/routes/transactions/breakdown/index.test.ts +++ b/x-pack/plugins/apm/server/routes/transactions/breakdown/index.test.ts @@ -27,7 +27,6 @@ const mockIndices: ApmIndicesConfig = { function getMockSetup(esResponse: any) { const clientSpy = jest.fn().mockReturnValueOnce(esResponse); return { - apmEventClient: { search: clientSpy } as any, internalClient: { search: clientSpy } as any, config: new Proxy( {}, @@ -39,87 +38,107 @@ function getMockSetup(esResponse: any) { }; } +function getMockApmEventClient(esResponse: any) { + const apmEventClientSpy = jest.fn().mockReturnValueOnce(esResponse); + return { apmEventClient: { search: apmEventClientSpy } as any }; +} + describe('getTransactionBreakdown', () => { - it('returns an empty array if no data is available', async () => { - const response = await getTransactionBreakdown({ - serviceName: 'myServiceName', - transactionType: 'request', - setup: getMockSetup(noDataResponse), - environment: ENVIRONMENT_ALL.value, - kuery: '', - start: 0, - end: 500000, + describe('when no data is available', () => { + const { config } = getMockSetup(noDataResponse); + const { apmEventClient } = getMockApmEventClient(noDataResponse); + it('returns an empty array if no data is available', async () => { + const response = await getTransactionBreakdown({ + serviceName: 'myServiceName', + transactionType: 'request', + config, + apmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 500000, + }); + + expect(Object.keys(response.timeseries).length).toBe(0); }); - - expect(Object.keys(response.timeseries).length).toBe(0); }); - it('returns a timeseries grouped by type and subtype', async () => { - const response = await getTransactionBreakdown({ - serviceName: 'myServiceName', - transactionType: 'request', - setup: getMockSetup(dataResponse), - environment: ENVIRONMENT_ALL.value, - kuery: '', - start: 0, - end: 500000, + describe('when data is returned', () => { + it('returns a timeseries grouped by type and subtype', async () => { + const { config } = getMockSetup(dataResponse); + const { apmEventClient } = getMockApmEventClient(dataResponse); + const response = await getTransactionBreakdown({ + serviceName: 'myServiceName', + transactionType: 'request', + config, + apmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 500000, + }); + + const { timeseries } = response; + + expect(timeseries.length).toBe(4); + + const appTimeseries = timeseries[0]; + expect(appTimeseries.title).toBe('app'); + expect(appTimeseries.type).toBe('areaStacked'); + expect(appTimeseries.hideLegend).toBe(false); + + // empty buckets should result in null values for visible types + expect(appTimeseries.data.length).toBe(276); + expect(appTimeseries.data.length).not.toBe(257); + + expect(appTimeseries.data[0].x).toBe(1561102380000); + + expect(appTimeseries.data[0].y).toBeCloseTo(0.8689440187037277); }); - const { timeseries } = response; - - expect(timeseries.length).toBe(4); - - const appTimeseries = timeseries[0]; - expect(appTimeseries.title).toBe('app'); - expect(appTimeseries.type).toBe('areaStacked'); - expect(appTimeseries.hideLegend).toBe(false); - - // empty buckets should result in null values for visible types - expect(appTimeseries.data.length).toBe(276); - expect(appTimeseries.data.length).not.toBe(257); - - expect(appTimeseries.data[0].x).toBe(1561102380000); - - expect(appTimeseries.data[0].y).toBeCloseTo(0.8689440187037277); - }); - - it('should not include more KPIs than MAX_KPIs', async () => { - // @ts-expect-error - constants.MAX_KPIS = 2; - - const response = await getTransactionBreakdown({ - serviceName: 'myServiceName', - transactionType: 'request', - setup: getMockSetup(dataResponse), - environment: ENVIRONMENT_ALL.value, - kuery: '', - start: 0, - end: 500000, + it('should not include more KPIs than MAX_KPIs', async () => { + const { config } = getMockSetup(dataResponse); + const { apmEventClient } = getMockApmEventClient(dataResponse); + // @ts-expect-error + constants.MAX_KPIS = 2; + + const response = await getTransactionBreakdown({ + serviceName: 'myServiceName', + transactionType: 'request', + config, + apmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 500000, + }); + const { timeseries } = response; + + expect(timeseries.map((serie) => serie.title)).toEqual(['app', 'http']); }); - const { timeseries } = response; - - expect(timeseries.map((serie) => serie.title)).toEqual(['app', 'http']); - }); - - it('fills in gaps for a given timestamp', async () => { - const response = await getTransactionBreakdown({ - serviceName: 'myServiceName', - transactionType: 'request', - setup: getMockSetup(dataResponse), - environment: ENVIRONMENT_ALL.value, - kuery: '', - start: 0, - end: 500000, + it('fills in gaps for a given timestamp', async () => { + const { config } = getMockSetup(dataResponse); + const { apmEventClient } = getMockApmEventClient(dataResponse); + const response = await getTransactionBreakdown({ + serviceName: 'myServiceName', + transactionType: 'request', + config, + apmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 500000, + }); + + const { timeseries } = response; + + const appTimeseries = timeseries.find((series) => series.title === 'app'); + + // missing values should be 0 if other span types do have data for that timestamp + expect( + (appTimeseries as NonNullable).data[1].y + ).toBe(0); }); - - const { timeseries } = response; - - const appTimeseries = timeseries.find((series) => series.title === 'app'); - - // missing values should be 0 if other span types do have data for that timestamp - expect((appTimeseries as NonNullable).data[1].y).toBe( - 0 - ); }); }); diff --git a/x-pack/plugins/apm/server/routes/transactions/breakdown/index.ts b/x-pack/plugins/apm/server/routes/transactions/breakdown/index.ts index 0c2293ec980c0..5630a4c0c475a 100644 --- a/x-pack/plugins/apm/server/routes/transactions/breakdown/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/breakdown/index.ts @@ -17,16 +17,18 @@ import { TRANSACTION_TYPE, TRANSACTION_NAME, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../lib/helpers/setup_request'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { getMetricsDateHistogramParams } from '../../../lib/helpers/metrics'; import { MAX_KPIS } from './constants'; import { getVizColorForIndex } from '../../../../common/viz_colors'; +import { APMConfig } from '../../..'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransactionBreakdown({ environment, kuery, - setup, + config, + apmEventClient, serviceName, transactionName, transactionType, @@ -35,15 +37,14 @@ export async function getTransactionBreakdown({ }: { environment: string; kuery: string; - setup: Setup; + config: APMConfig; + apmEventClient: APMEventClient; serviceName: string; transactionName?: string; transactionType: string; start: number; end: number; }) { - const { apmEventClient, config } = setup; - const subAggs = { sum_all_self_times: { sum: { diff --git a/x-pack/plugins/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts b/x-pack/plugins/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts index 0538832b6e84c..8a5ec8c83814d 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { Setup } from '../../lib/helpers/setup_request'; import { getFailedTransactionRate } from '../../lib/transaction_groups/get_failed_transaction_rate'; import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate'; +import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getFailedTransactionRatePeriods({ environment, @@ -14,7 +14,7 @@ export async function getFailedTransactionRatePeriods({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -25,7 +25,7 @@ export async function getFailedTransactionRatePeriods({ serviceName: string; transactionType: string; transactionName?: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; start: number; end: number; @@ -37,7 +37,7 @@ export async function getFailedTransactionRatePeriods({ serviceName, transactionTypes: [transactionType], transactionName, - setup, + apmEventClient, searchAggregatedTransactions, }; diff --git a/x-pack/plugins/apm/server/routes/transactions/get_latency_charts/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_latency_charts/index.ts index 47cc552fe4b54..be534d877d9fd 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_latency_charts/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_latency_charts/index.ts @@ -11,6 +11,7 @@ import { termQuery, } from '@kbn/observability-plugin/server'; import { + FAAS_ID, SERVICE_NAME, TRANSACTION_NAME, TRANSACTION_TYPE, @@ -23,13 +24,13 @@ import { getDurationFieldForTransactions, getProcessorEventForTransactions, } from '../../../lib/helpers/transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; import { getBucketSizeForAggregatedTransactions } from '../../../lib/helpers/get_bucket_size_for_aggregated_transactions'; import { getLatencyAggregation, getLatencyValue, } from '../../../lib/helpers/latency_aggregation_type'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export type LatencyChartsSearchResponse = Awaited< ReturnType @@ -41,27 +42,27 @@ function searchLatency({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, latencyAggregationType, start, end, offset, + serverlessId, }: { environment: string; kuery: string; serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; latencyAggregationType: LatencyAggregationType; start: number; end: number; offset?: string; + serverlessId?: string; }) { - const { apmEventClient } = setup; - const { startWithOffset, endWithOffset } = getOffsetInMs({ start, end, @@ -97,6 +98,7 @@ function searchLatency({ ...kqlQuery(kuery), ...termQuery(TRANSACTION_NAME, transactionName), ...termQuery(TRANSACTION_TYPE, transactionType), + ...termQuery(FAAS_ID, serverlessId), ], }, }, @@ -127,24 +129,26 @@ export async function getLatencyTimeseries({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, latencyAggregationType, start, end, offset, + serverlessId, }: { environment: string; kuery: string; serviceName: string; transactionType?: string; transactionName?: string; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; latencyAggregationType: LatencyAggregationType; start: number; end: number; offset?: string; + serverlessId?: string; }) { const response = await searchLatency({ environment, @@ -152,12 +156,13 @@ export async function getLatencyTimeseries({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, latencyAggregationType, start, end, offset, + serverlessId, }); if (!response.aggregations) { @@ -185,7 +190,7 @@ export async function getLatencyPeriods({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, latencyAggregationType, kuery, @@ -197,7 +202,7 @@ export async function getLatencyPeriods({ serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup; + apmEventClient: APMEventClient; searchAggregatedTransactions: boolean; latencyAggregationType: LatencyAggregationType; kuery: string; @@ -210,7 +215,7 @@ export async function getLatencyPeriods({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, kuery, environment, diff --git a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts index f3eab3707e1ed..9ca077744899e 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts @@ -11,24 +11,22 @@ import { TRACE_ID, TRANSACTION_ID, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../lib/helpers/setup_request'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getTransaction({ transactionId, traceId, - setup, + apmEventClient, start, end, }: { transactionId: string; traceId?: string; - setup: Setup; + apmEventClient: APMEventClient; start?: number; end?: number; }) { - const { apmEventClient } = setup; - const resp = await apmEventClient.search('get_transaction', { apm: { events: [ProcessorEvent.transaction], diff --git a/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts index ca3b3bba12307..0f27d37c2b0ab 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts @@ -10,14 +10,12 @@ import { TRACE_ID, PARENT_ID, } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; export async function getRootTransactionByTraceId( traceId: string, - setup: Setup + apmEventClient: APMEventClient ) { - const { apmEventClient } = setup; - const params = { apm: { events: [ProcessorEvent.transaction as const], diff --git a/x-pack/plugins/apm/server/routes/transactions/queries.test.ts b/x-pack/plugins/apm/server/routes/transactions/queries.test.ts index 4770dce0a1cb2..be11546ee20a1 100644 --- a/x-pack/plugins/apm/server/routes/transactions/queries.test.ts +++ b/x-pack/plugins/apm/server/routes/transactions/queries.test.ts @@ -22,11 +22,12 @@ describe('transaction queries', () => { }); it('fetches breakdown data for transactions', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTransactionBreakdown({ serviceName: 'foo', transactionType: 'bar', - setup, + config: setup.config, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -38,12 +39,13 @@ describe('transaction queries', () => { }); it('fetches breakdown data for transactions for a transaction name', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTransactionBreakdown({ serviceName: 'foo', transactionType: 'bar', transactionName: 'baz', - setup, + config: setup.config, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -55,14 +57,14 @@ describe('transaction queries', () => { }); it('fetches transaction trace samples', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTraceSamples({ serviceName: 'foo', transactionName: 'bar', transactionType: 'baz', traceId: 'qux', transactionId: 'quz', - setup, + apmEventClient, environment: ENVIRONMENT_ALL.value, kuery: '', start: 0, @@ -74,11 +76,11 @@ describe('transaction queries', () => { }); it('fetches a transaction', async () => { - mock = await inspectSearchParams((setup) => + mock = await inspectSearchParams((setup, apmEventClient) => getTransaction({ transactionId: 'foo', traceId: 'bar', - setup, + apmEventClient, start: 0, end: 50000, }) diff --git a/x-pack/plugins/apm/server/routes/transactions/route.ts b/x-pack/plugins/apm/server/routes/transactions/route.ts index 3bc4dbfe7aae7..b862fdd37cb5b 100644 --- a/x-pack/plugins/apm/server/routes/transactions/route.ts +++ b/x-pack/plugins/apm/server/routes/transactions/route.ts @@ -23,6 +23,7 @@ import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from '../default_api_types'; import { offsetRt } from '../../../common/comparison_rt'; import { getTraceSamples } from './trace_samples'; +import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const transactionGroupsMainStatisticsRoute = createApmServerRoute({ endpoint: @@ -57,7 +58,10 @@ const transactionGroupsMainStatisticsRoute = createApmServerRoute({ bucketSize: number; }> => { const { params } = resources; - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { path: { serviceName }, query: { @@ -69,9 +73,10 @@ const transactionGroupsMainStatisticsRoute = createApmServerRoute({ end, }, } = params; - + const { config } = setup; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + apmEventClient, + config, kuery, start, end, @@ -80,7 +85,8 @@ const transactionGroupsMainStatisticsRoute = createApmServerRoute({ return getServiceTransactionGroups({ environment, kuery, - setup, + config, + apmEventClient, serviceName, searchAggregatedTransactions, transactionType, @@ -139,7 +145,10 @@ const transactionGroupsDetailedStatisticsRoute = createApmServerRoute({ impact: number; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { @@ -158,7 +167,8 @@ const transactionGroupsDetailedStatisticsRoute = createApmServerRoute({ } = params; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -167,7 +177,7 @@ const transactionGroupsDetailedStatisticsRoute = createApmServerRoute({ return await getServiceTransactionGroupDetailedStatisticsPeriods({ environment, kuery, - setup, + apmEventClient, serviceName, transactionNames, searchAggregatedTransactions, @@ -221,7 +231,10 @@ const transactionLatencyChartsRoute = createApmServerRoute({ overallAvgDuration: null; }; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params, logger } = resources; const { serviceName } = params.path; @@ -237,7 +250,8 @@ const transactionLatencyChartsRoute = createApmServerRoute({ } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -249,7 +263,7 @@ const transactionLatencyChartsRoute = createApmServerRoute({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, logger, start, @@ -298,7 +312,7 @@ const transactionTraceSamplesRoute = createApmServerRoute({ ): Promise<{ traceSamples: Array<{ transactionId: string; traceId: string }>; }> => { - const setup = await setupRequest(resources); + const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName } = params.path; const { @@ -324,7 +338,7 @@ const transactionTraceSamplesRoute = createApmServerRoute({ traceId, sampleRangeFrom, sampleRangeTo, - setup, + apmEventClient, start, end, }); @@ -359,7 +373,10 @@ const transactionChartsBreakdownRoute = createApmServerRoute({ legendValue: string; }>; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; @@ -372,7 +389,8 @@ const transactionChartsBreakdownRoute = createApmServerRoute({ serviceName, transactionName, transactionType, - setup, + config: setup.config, + apmEventClient, start, end, }); @@ -416,7 +434,10 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ average: null; }; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; @@ -431,7 +452,8 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -443,7 +465,7 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -490,7 +512,10 @@ const transactionChartsColdstartRateRoute = createApmServerRoute({ average: null; }; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; @@ -498,7 +523,8 @@ const transactionChartsColdstartRateRoute = createApmServerRoute({ params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -509,7 +535,7 @@ const transactionChartsColdstartRateRoute = createApmServerRoute({ kuery, serviceName, transactionType, - setup, + apmEventClient, searchAggregatedTransactions, start, end, @@ -557,7 +583,10 @@ const transactionChartsColdstartRateByTransactionNameRoute = average: null; }; }> => { - const setup = await setupRequest(resources); + const [setup, apmEventClient] = await Promise.all([ + setupRequest(resources), + getApmEventClient(resources), + ]); const { params } = resources; const { serviceName } = params.path; @@ -572,7 +601,8 @@ const transactionChartsColdstartRateByTransactionNameRoute = } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ - ...setup, + config: setup.config, + apmEventClient, kuery, start, end, @@ -584,7 +614,7 @@ const transactionChartsColdstartRateByTransactionNameRoute = serviceName, transactionType, transactionName, - setup, + apmEventClient, searchAggregatedTransactions, start, end, diff --git a/x-pack/plugins/apm/server/routes/transactions/trace_samples/index.ts b/x-pack/plugins/apm/server/routes/transactions/trace_samples/index.ts index 572fa1a1c6d11..9fe3e7ff79335 100644 --- a/x-pack/plugins/apm/server/routes/transactions/trace_samples/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/trace_samples/index.ts @@ -18,7 +18,7 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; const TRACE_SAMPLES_SIZE = 500; @@ -32,7 +32,7 @@ export async function getTraceSamples({ traceId, sampleRangeFrom, sampleRangeTo, - setup, + apmEventClient, start, end, }: { @@ -45,13 +45,11 @@ export async function getTraceSamples({ traceId: string; sampleRangeFrom?: number; sampleRangeTo?: number; - setup: Setup; + apmEventClient: APMEventClient; start: number; end: number; }) { return withApmSpan('get_trace_samples', async () => { - const { apmEventClient } = setup; - const commonFilters = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, diff --git a/x-pack/plugins/apm/server/test_helpers/create_apm_users/authentication.ts b/x-pack/plugins/apm/server/test_helpers/create_apm_users/authentication.ts index f3d15ee6db21e..f4ea0629f848b 100644 --- a/x-pack/plugins/apm/server/test_helpers/create_apm_users/authentication.ts +++ b/x-pack/plugins/apm/server/test_helpers/create_apm_users/authentication.ts @@ -15,7 +15,7 @@ export enum ApmUsername { apmReadUserWithoutMlAccess = 'apm_read_user_without_ml_access', apmManageOwnAgentKeys = 'apm_manage_own_agent_keys', apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys', - apmMonitorIndices = 'apm_monitor_indices', + apmMonitorClusterAndIndices = 'apm_monitor_cluster_and_indices', } export enum ApmCustomRolename { @@ -23,7 +23,7 @@ export enum ApmCustomRolename { apmAnnotationsWriteUser = 'apm_annotations_write_user', apmManageOwnAgentKeys = 'apm_manage_own_agent_keys', apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys', - apmMonitorIndices = 'apm_monitor_indices', + apmMonitorClusterAndIndices = 'apm_monitor_cluster_and_indices', } export const customRoles = { @@ -77,7 +77,7 @@ export const customRoles = { }, ], }, - [ApmCustomRolename.apmMonitorIndices]: { + [ApmCustomRolename.apmMonitorClusterAndIndices]: { elasticsearch: { indices: [ { @@ -85,6 +85,7 @@ export const customRoles = { privileges: ['monitor'], }, ], + cluster: ['monitor'], }, }, }; @@ -118,9 +119,9 @@ export const users: Record< ApmCustomRolename.apmManageOwnAndCreateAgentKeys, ], }, - [ApmUsername.apmMonitorIndices]: { + [ApmUsername.apmMonitorClusterAndIndices]: { builtInRoleNames: ['viewer'], - customRoleNames: [ApmCustomRolename.apmMonitorIndices], + customRoleNames: [ApmCustomRolename.apmMonitorClusterAndIndices], }, }; diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx index c39e2b78d07c8..db69e4d78ea4f 100644 --- a/x-pack/plugins/apm/server/utils/test_helpers.tsx +++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx @@ -7,6 +7,7 @@ import type { ESSearchRequest, ESSearchResponse } from '@kbn/es-types'; import { APMConfig } from '..'; +import { APMEventClient } from '../lib/helpers/create_es_client/create_apm_event_client'; import { ApmIndicesConfig } from '../routes/settings/apm_indices/get_apm_indices'; interface Options { @@ -17,14 +18,16 @@ interface Options { } interface MockSetup { - apmEventClient: any; internalClient: any; config: APMConfig; indices: ApmIndicesConfig; } export async function inspectSearchParams( - fn: (mockSetup: MockSetup) => Promise, + fn: ( + mockSetup: MockSetup, + mockApmEventClient: APMEventClient + ) => Promise, options: Options = {} ) { const spy = jest.fn().mockImplementation(async (request) => { @@ -43,7 +46,7 @@ export async function inspectSearchParams( let response; let error; - + const mockApmEventClient = { search: spy } as any; const mockApmIndices: { [Property in keyof APMConfig['indices']]: string; } = { @@ -55,7 +58,6 @@ export async function inspectSearchParams( metric: 'myIndex', }; const mockSetup = { - apmEventClient: { search: spy } as any, internalClient: { search: spy } as any, config: new Proxy( {}, @@ -90,7 +92,7 @@ export async function inspectSearchParams( }, }; try { - response = await fn(mockSetup); + response = await fn(mockSetup, mockApmEventClient); } catch (err) { error = err; // we're only extracting the search params diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_autoplay_helper.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_autoplay_helper.test.tsx index 085a9093e8b8a..acbd425e1d245 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_autoplay_helper.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_autoplay_helper.test.tsx @@ -25,7 +25,7 @@ const getContextWrapper: (context: WorkpadRoutingContextType) => FC = {children}; describe('useAutoplayHelper', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); test('starts the timer when fullscreen and autoplay is on', () => { const context = getMockedContext({ isFullscreen: true, @@ -47,7 +47,7 @@ describe('useAutoplayHelper', () => { const { rerender } = renderHook(useAutoplayHelper, { wrapper: getContextWrapper(context) }); - jest.runTimersToTime(context.autoplayInterval - 1); + jest.advanceTimersByTime(context.autoplayInterval - 1); context.isAutoplayPaused = true; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_refresh_helper.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_refresh_helper.test.tsx index d502e634ede04..ac64f509b56b4 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_refresh_helper.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_refresh_helper.test.tsx @@ -37,7 +37,7 @@ const getContextWrapper: (context: WorkpadRoutingContextType) => FC = describe('useRefreshHelper', () => { beforeEach(() => { jest.resetAllMocks(); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); test('starts a timer to refresh', () => { @@ -73,7 +73,7 @@ describe('useRefreshHelper', () => { mockGetState.mockReturnValue(state); const { rerender } = renderHook(useRefreshHelper, { wrapper: getContextWrapper(context) }); - jest.runTimersToTime(context.refreshInterval - 1); + jest.advanceTimersByTime(context.refreshInterval - 1); expect(mockDispatch).not.toHaveBeenCalledWith(refreshAction); state.transient.inFlight = true; diff --git a/x-pack/plugins/canvas/storybook/storyshots.test.tsx b/x-pack/plugins/canvas/storybook/storyshots.skipped_test.tsx similarity index 96% rename from x-pack/plugins/canvas/storybook/storyshots.test.tsx rename to x-pack/plugins/canvas/storybook/storyshots.skipped_test.tsx index d880a31f446d3..1088113124578 100644 --- a/x-pack/plugins/canvas/storybook/storyshots.test.tsx +++ b/x-pack/plugins/canvas/storybook/storyshots.skipped_test.tsx @@ -5,6 +5,9 @@ * 2.0. */ +// This file is skipped +// @storybook/addon-storyshots is not supported in Jest 27+ https://github.com/storybookjs/storybook/issues/15916 + import fs from 'fs'; import { ReactChildren, createElement } from 'react'; import path from 'path'; diff --git a/x-pack/plugins/cases/public/components/links/index.test.tsx b/x-pack/plugins/cases/public/components/links/index.test.tsx index e2da1a28261e7..2fd05e45ade25 100644 --- a/x-pack/plugins/cases/public/components/links/index.test.tsx +++ b/x-pack/plugins/cases/public/components/links/index.test.tsx @@ -74,7 +74,7 @@ describe('Configuration button', () => { test('it shows the tooltip when hovering the button', () => { // Use fake timers so we don't have to wait for the EuiToolTip timeout - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const msgTooltip = 'My message tooltip'; const titleTooltip = 'My title'; diff --git a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx index 510be840d5436..bb663dd89bd10 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx @@ -28,7 +28,7 @@ const openLensModal = jest.fn(); describe('useUserActionsHandler', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); jest.spyOn(global, 'setTimeout'); }); diff --git a/x-pack/plugins/cloud_integrations/cloud_experiments/common/metadata_service/metadata_service.test.ts b/x-pack/plugins/cloud_integrations/cloud_experiments/common/metadata_service/metadata_service.test.ts index 8764eb434213e..6e79b5e4ebf03 100644 --- a/x-pack/plugins/cloud_integrations/cloud_experiments/common/metadata_service/metadata_service.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_experiments/common/metadata_service/metadata_service.test.ts @@ -20,7 +20,7 @@ jest.mock('rxjs', () => { }); describe('MetadataService', () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); let metadataService: MetadataService; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts index e6107874b6d5d..f086f20956778 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts @@ -31,47 +31,74 @@ describe('Cloud Links Plugin - public', () => { plugin.stop(); }); - test('calls maybeAddCloudLinks when cloud and security are enabled and it is an authenticated page', () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); - expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(1); - }); + describe('Onboarding Setup Guide link registration', () => { + test('registers the Onboarding Setup Guide link when cloud is enabled and it is an authenticated page', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; + plugin.start(coreStart, { cloud }); + expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).toHaveBeenCalledTimes(1); + }); - test('does not call maybeAddCloudLinks when security is disabled', () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - plugin.start(coreStart, { cloud }); - expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); - }); + test('does not register the Onboarding Setup Guide link when cloud is enabled but it is an unauthenticated page', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; + plugin.start(coreStart, { cloud }); + expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled(); + }); - test('does not call maybeAddCloudLinks when the page is anonymous', () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); - const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); - expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + test('does not register the Onboarding Setup Guide link when cloud is not enabled', () => { + const coreStart = coreMock.createStart(); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: false }; + plugin.start(coreStart, { cloud }); + expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled(); + }); }); - test('does not call maybeAddCloudLinks when cloud is disabled', () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - const security = securityMock.createStart(); - plugin.start(coreStart, { security }); - expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); - }); + describe('maybeAddCloudLinks', () => { + test('calls maybeAddCloudLinks when cloud and security are enabled and it is an authenticated page', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; + const security = securityMock.createStart(); + plugin.start(coreStart, { cloud, security }); + expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(1); + }); + + test('does not call maybeAddCloudLinks when security is disabled', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; + plugin.start(coreStart, { cloud }); + expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + }); + + test('does not call maybeAddCloudLinks when the page is anonymous', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; + const security = securityMock.createStart(); + plugin.start(coreStart, { cloud, security }); + expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + }); + + test('does not call maybeAddCloudLinks when cloud is disabled', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); + const security = securityMock.createStart(); + plugin.start(coreStart, { security }); + expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + }); - test('does not call maybeAddCloudLinks when isCloudEnabled is false', () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - const cloud = { ...cloudMock.createStart(), isCloudEnabled: false }; - const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); - expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + test('does not call maybeAddCloudLinks when isCloudEnabled is false', () => { + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); + const cloud = { ...cloudMock.createStart(), isCloudEnabled: false }; + const security = securityMock.createStart(); + plugin.start(coreStart, { cloud, security }); + expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); + }); }); }); }); diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx similarity index 58% rename from x-pack/plugins/cloud_integrations/cloud_links/public/plugin.ts rename to x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx index 7fbf7a8a65064..0d64ed13cde9f 100755 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import type { CoreStart, Plugin } from '@kbn/core/public'; import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; @@ -26,12 +28,18 @@ export class CloudLinksPlugin public setup() {} public start(core: CoreStart, { cloud, security }: CloudLinksDepsStart) { - if ( - cloud?.isCloudEnabled && - security && - !core.http.anonymousPaths.isAnonymous(window.location.pathname) - ) { - maybeAddCloudLinks({ security, chrome: core.chrome, cloud }); + if (cloud?.isCloudEnabled && !core.http.anonymousPaths.isAnonymous(window.location.pathname)) { + core.chrome.registerGlobalHelpExtensionMenuLink({ + linkType: 'custom', + href: core.http.basePath.prepend('/app/home#/getting_started'), + content: , + 'data-test-subj': 'cloudOnboardingSetupGuideLink', + priority: 1000, // We want this link to be at the very top. + }); + + if (security) { + maybeAddCloudLinks({ security, chrome: core.chrome, cloud }); + } } } diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index 764cb49dae8d2..a956800136483 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -49,3 +49,11 @@ export const CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE = 'csp-rule-template'; export const CLOUDBEAT_VANILLA = 'cloudbeat/cis_k8s'; // Integration input export const CLOUDBEAT_EKS = 'cloudbeat/cis_eks'; // Integration input + +export const LOCAL_STORAGE_PAGE_SIZE_LATEST_FINDINGS_KEY = 'cloudPosture:latestFindings:pageSize'; +export const LOCAL_STORAGE_PAGE_SIZE_RESOURCE_FINDINGS_KEY = + 'cloudPosture:resourceFindings:pageSize'; +export const LOCAL_STORAGE_PAGE_SIZE_FINDINGS_BY_RESOURCE_KEY = + 'cloudPosture:findingsByResource:pageSize'; +export const LOCAL_STORAGE_PAGE_SIZE_BENCHMARK_KEY = 'cloudPosture:benchmark:pageSize'; +export const LOCAL_STORAGE_PAGE_SIZE_RULES_KEY = 'cloudPosture:rules:pageSize'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx index fce512d95315b..ce615733e4b98 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import { EuiFieldSearch, EuiFieldSearchProps, @@ -30,6 +31,7 @@ import { } from './use_csp_benchmark_integrations'; import { extractErrorMessage } from '../../../common/utils/helpers'; import * as TEST_SUBJ from './test_subjects'; +import { LOCAL_STORAGE_PAGE_SIZE_BENCHMARK_KEY } from '../../../common/constants'; const SEARCH_DEBOUNCE_MS = 300; @@ -126,10 +128,14 @@ const BenchmarkSearchField = ({ }; export const Benchmarks = () => { + const [pageSize, setPageSize] = useLocalStorage( + LOCAL_STORAGE_PAGE_SIZE_BENCHMARK_KEY, + 10 + ); const [query, setQuery] = useState({ name: '', page: 1, - perPage: 10, + perPage: pageSize || 10, sortField: 'package_policy.name', sortOrder: 'asc', }); @@ -169,7 +175,7 @@ export const Benchmarks = () => { error={queryResult.error ? extractErrorMessage(queryResult.error) : undefined} loading={queryResult.isFetching} pageIndex={query.page} - pageSize={query.perPage} + pageSize={pageSize || query.perPage} sorting={{ // @ts-expect-error - EUI types currently do not support sorting by nested fields sort: { field: query.sortField, direction: query.sortOrder }, @@ -177,6 +183,7 @@ export const Benchmarks = () => { }} totalItemCount={totalItemCount} setQuery={({ page, sort }) => { + setPageSize(page.size); setQuery((current) => ({ ...current, page: page.index, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings/latest_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings/latest_findings_container.tsx index 3294ee8ec4965..92b6ca6dcc68e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings/latest_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings/latest_findings_container.tsx @@ -8,6 +8,7 @@ import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiBottomBar, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import type { Evaluation } from '../../../../common/types'; import { CloudPosturePageTitle } from '../../../components/cloud_posture_page_title'; import type { FindingsBaseProps } from '../types'; @@ -31,6 +32,7 @@ import { FindingsGroupBySelector } from '../layout/findings_group_by_selector'; import { useUrlQuery } from '../../../common/hooks/use_url_query'; import { ErrorCallout } from '../layout/error_callout'; import { getLimitProperties } from '../utils/get_limit_properties'; +import { LOCAL_STORAGE_PAGE_SIZE_LATEST_FINDINGS_KEY } from '../../../../common/constants'; export const getDefaultQuery = ({ query, @@ -48,7 +50,10 @@ const MAX_ITEMS = 500; export const LatestFindingsContainer = ({ dataView }: FindingsBaseProps) => { const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); - + const [pageSize, setPageSize] = useLocalStorage( + LOCAL_STORAGE_PAGE_SIZE_LATEST_FINDINGS_KEY, + urlQuery.pageSize + ); /** * Page URL query to ES query */ @@ -62,7 +67,10 @@ export const LatestFindingsContainer = ({ dataView }: FindingsBaseProps) => { * Page ES query result */ const findingsGroupByNone = useLatestFindings({ - ...getPaginationQuery({ pageIndex: urlQuery.pageIndex, pageSize: urlQuery.pageSize }), + ...getPaginationQuery({ + pageIndex: urlQuery.pageIndex, + pageSize: pageSize || urlQuery.pageSize, + }), query: baseEsQuery.query, sort: urlQuery.sort, enabled: !baseEsQuery.error, @@ -137,20 +145,21 @@ export const LatestFindingsContainer = ({ dataView }: FindingsBaseProps) => { loading={findingsGroupByNone.isFetching} items={findingsGroupByNone.data?.page || []} pagination={getPaginationTableParams({ - pageSize: urlQuery.pageSize, + pageSize: pageSize || urlQuery.pageSize, pageIndex: urlQuery.pageIndex, totalItemCount: limitedTotalItemCount, })} sorting={{ sort: { field: urlQuery.sort.field, direction: urlQuery.sort.direction }, }} - setTableOptions={({ page, sort }) => + setTableOptions={({ page, sort }) => { + setPageSize(page.size); setUrlQuery({ sort, pageIndex: page.index, pageSize: page.size, - }) - } + }); + }} onAddFilter={(field, value, negate) => setUrlQuery({ pageIndex: 0, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_container.tsx index e9ce59fe9f0c0..982fd12fbc06f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_container.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import type { Evaluation } from '../../../../common/types'; import { CloudPosturePageTitle } from '../../../components/cloud_posture_page_title'; import { FindingsSearchBar } from '../layout/findings_search_bar'; @@ -30,6 +31,7 @@ import { findingsNavigation } from '../../../common/navigation/constants'; import { ResourceFindings } from './resource_findings/resource_findings_container'; import { ErrorCallout } from '../layout/error_callout'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; +import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_BY_RESOURCE_KEY } from '../../../../common/constants'; const getDefaultQuery = ({ query, @@ -59,6 +61,10 @@ export const FindingsByResourceContainer = ({ dataView }: FindingsBaseProps) => const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => { const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); + const [pageSize, setPageSize] = useLocalStorage( + LOCAL_STORAGE_PAGE_SIZE_FINDINGS_BY_RESOURCE_KEY, + urlQuery.pageSize + ); /** * Page URL query to ES query @@ -73,7 +79,10 @@ const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => { * Page ES query result */ const findingsGroupByResource = useFindingsByResource({ - ...getPaginationQuery(urlQuery), + ...getPaginationQuery({ + pageIndex: urlQuery.pageIndex, + pageSize: pageSize || urlQuery.pageSize, + }), sortDirection: urlQuery.sortDirection, query: baseEsQuery.query, enabled: !baseEsQuery.error, @@ -148,17 +157,18 @@ const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => { loading={findingsGroupByResource.isFetching} items={findingsGroupByResource.data?.page || []} pagination={getPaginationTableParams({ - pageSize: urlQuery.pageSize, + pageSize: pageSize || urlQuery.pageSize, pageIndex: urlQuery.pageIndex, totalItemCount: findingsGroupByResource.data?.total || 0, })} - setTableOptions={({ sort, page }) => + setTableOptions={({ sort, page }) => { + setPageSize(page.size); setUrlQuery({ sortDirection: sort?.direction, pageIndex: page.index, pageSize: page.size, - }) - } + }); + }} sorting={{ sort: { field: 'failed_findings', direction: urlQuery.sortDirection }, }} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx index 75997efaf6294..e61415b7d0af1 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx @@ -15,6 +15,7 @@ import { Link, useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { generatePath } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import { CspInlineDescriptionList } from '../../../../components/csp_inline_description_list'; import type { Evaluation } from '../../../../../common/types'; import { CspFinding } from '../../../../../common/schemas/csp_finding'; @@ -37,6 +38,7 @@ import { ResourceFindingsTable } from './resource_findings_table'; import { FindingsSearchBar } from '../../layout/findings_search_bar'; import { ErrorCallout } from '../../layout/error_callout'; import { FindingsDistributionBar } from '../../layout/findings_distribution_bar'; +import { LOCAL_STORAGE_PAGE_SIZE_RESOURCE_FINDINGS_KEY } from '../../../../../common/constants'; const getDefaultQuery = ({ query, @@ -90,6 +92,10 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { const params = useParams<{ resourceId: string }>(); const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); + const [pageSize, setPageSize] = useLocalStorage( + LOCAL_STORAGE_PAGE_SIZE_RESOURCE_FINDINGS_KEY, + urlQuery.pageSize + ); /** * Page URL query to ES query @@ -105,7 +111,7 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { */ const resourceFindings = useResourceFindings({ ...getPaginationQuery({ - pageSize: urlQuery.pageSize, + pageSize: pageSize || urlQuery.pageSize, pageIndex: urlQuery.pageIndex, }), sort: urlQuery.sort, @@ -195,16 +201,17 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { loading={resourceFindings.isFetching} items={resourceFindings.data?.page || []} pagination={getPaginationTableParams({ - pageSize: urlQuery.pageSize, + pageSize: pageSize || urlQuery.pageSize, pageIndex: urlQuery.pageIndex, totalItemCount: resourceFindings.data?.total || 0, })} sorting={{ sort: { field: urlQuery.sort.field, direction: urlQuery.sort.direction }, }} - setTableOptions={({ page, sort }) => - setUrlQuery({ pageIndex: page.index, pageSize: page.size, sort }) - } + setTableOptions={({ page, sort }) => { + setPageSize(page.size); + setUrlQuery({ pageIndex: page.index, pageSize: page.size, sort }); + }} onAddFilter={(field, value, negate) => setUrlQuery({ pageIndex: 0, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx index cc5f10a0bf061..84f39bb150c26 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx @@ -7,6 +7,7 @@ import React, { useState, useMemo } from 'react'; import { EuiPanel, EuiSpacer } from '@elastic/eui'; import { useParams } from 'react-router-dom'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import { extractErrorMessage, createCspRuleSearchFilterByPackagePolicy, @@ -22,6 +23,7 @@ import { } from './use_csp_rules'; import * as TEST_SUBJECTS from './test_subjects'; import { RuleFlyout } from './rules_flyout'; +import { LOCAL_STORAGE_PAGE_SIZE_RULES_KEY } from '../../../common/constants'; interface RulesPageData { rules_page: RuleSavedObject[]; @@ -68,6 +70,7 @@ export type PageUrlParams = Record<'policyId' | 'packagePolicyId', string>; export const RulesContainer = () => { const params = useParams(); const [selectedRuleId, setSelectedRuleId] = useState(null); + const [pageSize, setPageSize] = useLocalStorage(LOCAL_STORAGE_PAGE_SIZE_RULES_KEY, 10); const [rulesQuery, setRulesQuery] = useState({ filter: createCspRuleSearchFilterByPackagePolicy({ packagePolicyId: params.packagePolicyId, @@ -75,7 +78,7 @@ export const RulesContainer = () => { }), search: '', page: 0, - perPage: 10, + perPage: pageSize || 10, }); const { data, status, error } = useFindCspRules({ @@ -105,11 +108,12 @@ export const RulesContainer = () => { total={rulesPageData.total} error={rulesPageData.error} loading={rulesPageData.loading} - perPage={rulesQuery.perPage} + perPage={pageSize || rulesQuery.perPage} page={rulesQuery.page} - setPagination={(paginationQuery) => - setRulesQuery((currentQuery) => ({ ...currentQuery, ...paginationQuery })) - } + setPagination={(paginationQuery) => { + setPageSize(paginationQuery.perPage); + setRulesQuery((currentQuery) => ({ ...currentQuery, ...paginationQuery })); + }} setSelectedRuleId={setSelectedRuleId} selectedRuleId={selectedRuleId} /> diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js index 16d38d42d46b2..50e984eec194e 100644 --- a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js @@ -17,7 +17,7 @@ describe('', () => { let httpRequestsMockHelpers; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); ({ httpRequestsMockHelpers } = setupEnvironment()); }); diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/field_type_icon/field_type_icon.test.tsx b/x-pack/plugins/data_visualizer/public/application/common/components/field_type_icon/field_type_icon.test.tsx index 9962937fa80dc..771b27ace1c5b 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/field_type_icon/field_type_icon.test.tsx +++ b/x-pack/plugins/data_visualizer/public/application/common/components/field_type_icon/field_type_icon.test.tsx @@ -19,9 +19,10 @@ describe('FieldTypeIcon', () => { expect(typeIconComponent).toMatchSnapshot(); }); - test(`render with tooltip and test hovering`, () => { + // TODO: Broken with Jest 27 + test.skip(`render with tooltip and test hovering`, () => { // Use fake timers so we don't have to wait for the EuiToolTip timeout - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const typeIconComponent = mount( diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts index 7b281208f79e8..a0610dc546fbf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts @@ -97,7 +97,7 @@ describe('addAnalyticsCollectionLogic', () => { describe('listeners', () => { describe('onApiSuccess', () => { it('should flash a success toast and navigate to collection view', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const { navigateToUrl } = mockKibanaValues; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.test.ts index 08ca206671de0..baaea238fa6b4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.test.ts @@ -57,7 +57,7 @@ describe('deleteAnalyticsCollectionLogic', () => { it('calls makeRequest on deleteAnalyticsCollections', async () => { const collectionName = 'name'; - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); DeleteAnalyticsCollectionLogic.actions.makeRequest = jest.fn(); DeleteAnalyticsCollectionLogic.actions.deleteAnalyticsCollection(collectionName); jest.advanceTimersByTime(150); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts index 614f3506b4ef9..17f3ab989162d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts @@ -119,7 +119,7 @@ describe('ApiLogsLogic', () => { describe('listeners', () => { describe('pollForApiLogs', () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const setIntervalSpy = jest.spyOn(global, 'setInterval'); it('starts a poll that calls fetchApiLogs at set intervals', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts index 59ec64c69d5a8..9064d1185a3d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts @@ -73,7 +73,7 @@ describe('CrawlerLogic', () => { beforeEach(() => { jest.clearAllMocks(); - jest.useFakeTimers(); // this should be run before every test to reset these mocks + jest.useFakeTimers('legacy'); // this should be run before every test to reset these mocks mount(); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts index 4e25477d65dbf..4ea8dd55ffb44 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts @@ -380,7 +380,7 @@ describe('CurationLogic', () => { }); describe('updateCuration', () => { - beforeAll(() => jest.useFakeTimers()); + beforeAll(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); it('should make a PUT API call with queries and promoted/hidden IDs to update', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts index d82b4f5d4b055..1bb1a815d2364 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts @@ -255,7 +255,7 @@ describe('EngineLogic', () => { }); describe('pollEmptyEngine', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); afterEach(() => jest.clearAllTimers()); afterAll(() => jest.useRealTimers()); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts index fba8b118d4d24..a4ea5595bba3a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts @@ -329,7 +329,7 @@ describe('LogRetentionLogic', () => { }); describe('fetchLogRetention', () => { - beforeAll(() => jest.useFakeTimers()); + beforeAll(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); describe('isLogRetentionUpdating', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts index bf0bad4f1088a..f413fefb7f89b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts @@ -341,7 +341,7 @@ describe('RelevanceTuningLogic', () => { describe('getSearchResults', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts index ee20fab3da66c..6712a32c94bcc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts @@ -83,7 +83,7 @@ describe('SampleResponseLogic', () => { describe('listeners', () => { describe('getSearchResults', () => { - beforeAll(() => jest.useFakeTimers()); + beforeAll(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); it('makes a search API request and calls getSearchResultsSuccess with the first result of the response', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search/search_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search/search_logic.test.ts index a56d2f7d5c949..ab8426dce3636 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search/search_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search/search_logic.test.ts @@ -78,7 +78,7 @@ describe('SearchLogic', () => { describe('listeners', () => { describe('search', () => { - beforeAll(() => jest.useFakeTimers()); + beforeAll(() => jest.useFakeTimers('legacy')); afterAll(() => jest.useRealTimers()); it('should make a GET API call with a search query', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/add_connector_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/add_connector_logic.test.ts index e4b817f3d5973..7487a7790f797 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/add_connector_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/add_connector_logic.test.ts @@ -53,7 +53,7 @@ describe('AddConnectorLogic', () => { describe('apiSuccess', () => { it('navigates to correct spot and flashes success toast', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); AddConnectorApiLogic.actions.apiSuccess({ indexName: 'success' } as any); await nextTick(); jest.advanceTimersByTime(1001); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_search_index_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_search_index_logic.test.ts index f5ae61dc75dd9..8f22ba28b8dc3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_search_index_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_search_index_logic.test.ts @@ -86,7 +86,7 @@ describe('NewSearchIndexLogic', () => { }); }); it('calls makeRequest on whether API exists with a 150ms debounce', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); NewSearchIndexLogic.actions.makeRequest = jest.fn(); NewSearchIndexLogic.actions.setRawName('indexname'); await nextTick(); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_form.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_form.tsx index b0722ca50d2c7..e3d38256e9642 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_form.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_form.tsx @@ -19,6 +19,7 @@ import { EuiFieldText, EuiSpacer, EuiText, + EuiFormControlLayout, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -56,13 +57,14 @@ export const AddDomainForm: React.FC = () => { > - setAddDomainFormInputValue(e.target.value)} - fullWidth - /> + setAddDomainFormInputValue('') }}> + setAddDomainFormInputValue(e.target.value)} + fullWidth + /> + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/validation_step_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/validation_step_panel.tsx index 07e86b5f92d9e..fb33f620f82a7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/validation_step_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/validation_step_panel.tsx @@ -10,10 +10,12 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, + EuiLink, EuiMarkdownFormat, EuiPanel, EuiSpacer, EuiTitle, + getDefaultEuiMarkdownProcessingPlugins, } from '@elastic/eui'; import { CrawlerDomainValidationStep } from '../../../../../api/crawler/types'; @@ -27,6 +29,9 @@ interface ValidationStepPanelProps { step: CrawlerDomainValidationStep; } +const processingPlugins = getDefaultEuiMarkdownProcessingPlugins(); +processingPlugins[1][1].components.a = (props) => ; + export const ValidationStepPanel: React.FC = ({ step, label, @@ -49,7 +54,11 @@ export const ValidationStepPanel: React.FC = ({ {showErrorMessage && ( <> - + {step.message || ''} {action && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_table.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_table.tsx index 44a22f258b506..c86fc2b3a20dc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_table.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { EuiBasicTableColumn, EuiBasicTable } from '@elastic/eui'; +import { EuiBasicTableColumn, EuiBasicTable, EuiButtonIcon, EuiCopy } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -39,18 +39,23 @@ export const DomainsTable: React.FC = () => { { field: 'url', name: i18n.translate('xpack.enterpriseSearch.crawler.domainsTable.column.domainURL', { - defaultMessage: 'Domain URL', + defaultMessage: 'Domain', }), render: (_, domain: CrawlerDomain) => ( - - {domain.url} - + <> + + {(copy) => } + + + {domain.url} + + ), }, { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents_logic.test.ts index b927e6a5738e7..1bd1e1a405ee3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents_logic.test.ts @@ -85,7 +85,7 @@ describe('DocumentsLogic', () => { describe('listeners', () => { describe('setSearchQuery', () => { it('make documents apiRequest request after 250ms debounce', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); DocumentsLogic.actions.makeRequest = jest.fn(); DocumentsLogic.actions.setSearchQuery('test'); await nextTick(); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.test.ts index e09b66051e4aa..1b0a11d17f546 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.test.ts @@ -199,7 +199,7 @@ describe('IndexViewLogic', () => { describe('createNewFetchIndexTimeout', () => { it('should trigger fetchIndex after timeout', async () => { IndexViewLogic.actions.fetchIndex = jest.fn(); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); IndexViewLogic.actions.createNewFetchIndexTimeout(1); expect(IndexViewLogic.actions.fetchIndex).not.toHaveBeenCalled(); jest.advanceTimersByTime(2); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts index ff761b17e7388..d9b6a6248ce3b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts @@ -315,7 +315,7 @@ describe('IndicesLogic', () => { expect(IndicesLogic.actions.closeDeleteModal).toHaveBeenCalled(); }); it('calls makeRequest on fetchIndices', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); IndicesLogic.actions.makeRequest = jest.fn(); IndicesLogic.actions.fetchIndices({ meta: DEFAULT_META, returnHiddenIndices: false }); jest.advanceTimersByTime(150); @@ -326,7 +326,7 @@ describe('IndicesLogic', () => { }); }); it('calls makeRequest once on two fetchIndices calls within 150ms', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); IndicesLogic.actions.makeRequest = jest.fn(); IndicesLogic.actions.fetchIndices({ meta: DEFAULT_META, returnHiddenIndices: false }); jest.advanceTimersByTime(130); @@ -341,7 +341,7 @@ describe('IndicesLogic', () => { expect(IndicesLogic.actions.makeRequest).toHaveBeenCalledTimes(1); }); it('calls makeRequest twice on two fetchIndices calls outside 150ms', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); IndicesLogic.actions.makeRequest = jest.fn(); IndicesLogic.actions.fetchIndices({ meta: DEFAULT_META, returnHiddenIndices: false }); jest.advanceTimersByTime(150); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts index 75c9010ae9be5..a610cdc887d98 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts @@ -80,7 +80,7 @@ describe('SourcesLogic', () => { }; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); jest.clearAllMocks(); mount(); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts index bc82c95871676..a167c5a1c11c3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts @@ -239,7 +239,7 @@ describe('GroupsLogic', () => { }; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index c9ccd1841cf76..df7fee347161d 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -223,7 +223,7 @@ describe('callEnterpriseSearchConfigAPI', () => { }); it('handles timeouts', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // Warning callEnterpriseSearchConfigAPI(mockDependencies); diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors.ts index 12902b896e0d8..4a2ba80ca43ab 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors.ts @@ -202,7 +202,7 @@ export const fetchMlInferencePipelineProcessors = async ( indexName: string ): Promise => { if (!trainedModelsProvider) { - return Promise.reject(new Error('Machine Learning is not enabled')); + throw new Error('Machine Learning is not enabled'); } const allMlPipelines = await fetchMlInferencePipelines(client); diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.test.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.test.ts index b05a9bb15d5e8..0765fafcc9d1d 100644 --- a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.test.ts @@ -105,10 +105,10 @@ describe('getMlInferencePipelines', () => { expect( (actualPipelines.pipeline1.processors as IngestProcessorContainer[])[1].inference?.model_id - ).toBeDefined(); + ).toEqual('model1'); expect( (actualPipelines.pipeline2.processors as IngestProcessorContainer[])[1].inference?.model_id - ).toBeDefined(); + ).toEqual('model2'); expect( (actualPipelines.pipeline3.processors as IngestProcessorContainer[])[1].inference?.model_id ).toEqual(''); // Redacted model ID @@ -117,7 +117,7 @@ describe('getMlInferencePipelines', () => { ).toEqual(''); expect( (actualPipelines.pipeline4.processors as IngestProcessorContainer[])[2].inference?.model_id - ).toBeDefined(); + ).toEqual('model2'); expect( (actualPipelines.pipeline4.processors as IngestProcessorContainer[])[3].inference?.model_id ).toEqual(''); diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.ts index 4bdf7e95d4a06..2dfc6951b2224 100644 --- a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.ts +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/get_ml_inference_pipelines.ts @@ -20,7 +20,7 @@ export const getMlInferencePipelines = async ( trainedModelsProvider: MlTrainedModels | undefined ): Promise> => { if (!trainedModelsProvider) { - return Promise.reject(new Error('Machine Learning is not enabled')); + throw new Error('Machine Learning is not enabled'); } // Fetch all ML inference pipelines and trained models that are accessible in the current @@ -37,17 +37,22 @@ export const getMlInferencePipelines = async ( // Process pipelines: check if the model_id is one of the redacted ones, if so, redact it in the // result as well - const inferencePipelinesResult: Record = {}; - Object.entries(fetchedInferencePipelines).forEach(([name, inferencePipeline]) => { - inferencePipelinesResult[name] = { - ...inferencePipeline, - processors: inferencePipeline.processors?.map((processor) => - redactModelIdIfInaccessible(processor, accessibleModelIds) - ), - }; - }); + const inferencePipelinesResult: Record = Object.entries( + fetchedInferencePipelines + ).reduce( + (currentPipelines, [name, inferencePipeline]) => ({ + ...currentPipelines, + [name]: { + ...inferencePipeline, + processors: inferencePipeline.processors?.map((processor) => + redactModelIdIfInaccessible(processor, accessibleModelIds) + ), + }, + }), + {} + ); - return Promise.resolve(inferencePipelinesResult); + return inferencePipelinesResult; }; /** diff --git a/x-pack/plugins/features/common/sub_feature.ts b/x-pack/plugins/features/common/sub_feature.ts index 2795e50bce473..58142fd88c0c3 100644 --- a/x-pack/plugins/features/common/sub_feature.ts +++ b/x-pack/plugins/features/common/sub_feature.ts @@ -16,6 +16,17 @@ export interface SubFeatureConfig { /** Display name for this sub-feature */ name: string; + /** + * Whether or not this privilege should only be granted to `All Spaces *`. Should be used for features that do not + * support Spaces. Defaults to `false`. + */ + requireAllSpaces?: boolean; + + /** + * Optional message to display on the Role Management screen when configuring permissions for this feature. + */ + privilegesTooltip?: string; + /** Collection of privilege groups */ privilegeGroups: readonly SubFeaturePrivilegeGroupConfig[]; } @@ -90,6 +101,10 @@ export class SubFeature { return this.config.privilegeGroups; } + public get requireAllSpaces() { + return this.config.requireAllSpaces ?? false; + } + public toRaw() { return { ...this.config }; } diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index 30b2ddea3d7d5..05d172887d870 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -163,6 +163,8 @@ const kibanaMutuallyExclusiveSubFeaturePrivilegeSchema = const kibanaSubFeatureSchema = schema.object({ name: schema.string(), + requireAllSpaces: schema.maybe(schema.boolean()), + privilegesTooltip: schema.maybe(schema.string()), privilegeGroups: schema.maybe( schema.arrayOf( schema.oneOf([ diff --git a/x-pack/plugins/files/common/constants.ts b/x-pack/plugins/files/common/constants.ts index be0bfa3ca80c4..665945c1c65c1 100644 --- a/x-pack/plugins/files/common/constants.ts +++ b/x-pack/plugins/files/common/constants.ts @@ -27,3 +27,5 @@ export const FILE_SHARE_SO_TYPE = 'fileShare'; * The name of the fixed size ES-backed blob store */ export const ES_FIXED_SIZE_INDEX_BLOB_STORE = 'esFixedSizeIndex' as const; + +export const FILES_MANAGE_PRIVILEGE = 'files:manageFiles' as const; diff --git a/x-pack/plugins/files/kibana.json b/x-pack/plugins/files/kibana.json index ad83b24ef0842..47637d78fa0de 100755 --- a/x-pack/plugins/files/kibana.json +++ b/x-pack/plugins/files/kibana.json @@ -9,7 +9,6 @@ "description": "File upload, download, sharing, and serving over HTTP implementation in Kibana.", "server": true, "ui": true, - "requiredPlugins": [], "requiredBundles": ["kibanaUtils"], "optionalPlugins": ["security", "usageCollection"] } diff --git a/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx b/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx index 4c290b1b114e7..88c77f36a6c00 100644 --- a/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx +++ b/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx @@ -58,11 +58,6 @@ export const FileCard: FunctionComponent = ({ file }) => { `} meta={file.meta as FileImageMetadata} src={client.getDownloadHref({ id: file.id, fileKind: kind })} - // There is an issue where the intersection observer does not fire reliably. - // I'm not sure if this is becuause of the image being in a modal - // The result is that the image does not always get loaded. - // TODO: Investigate this behaviour further - lazy={false} /> ) : (
this.setIsLoading(true))).subscribe(), this.internalIsLoading$ .pipe(debounceTime(100), distinctUntilChanged()) .subscribe(this.isLoading$), ]; } + private readonly requests$ = combineLatest([ + this.currentPage$.pipe(distinctUntilChanged()), + this.query$.pipe(distinctUntilChanged(), debounceTime(100)), + this.retry$, + ]); + /** * File objects we have loaded on the front end, stored here so that it can * easily be passed to all relevant UI. @@ -74,11 +81,7 @@ export class FilePickerState { * @note This is not explicitly kept in sync with the selected files! * @note This is not explicitly kept in sync with the selected files! */ - public readonly files$ = combineLatest([ - this.currentPage$.pipe(distinctUntilChanged()), - this.query$.pipe(distinctUntilChanged(), debounceTime(100)), - this.retry$, - ]).pipe( + public readonly files$ = this.requests$.pipe( switchMap(([page, query]) => this.sendRequest(page, query)), tap(({ total }) => this.updateTotalPages({ total })), tap(({ total }) => this.hasFiles$.next(Boolean(total))), diff --git a/x-pack/plugins/files/public/components/image/components/img.tsx b/x-pack/plugins/files/public/components/image/components/img.tsx index 295b062ca1fd8..953eb93a19917 100644 --- a/x-pack/plugins/files/public/components/image/components/img.tsx +++ b/x-pack/plugins/files/public/components/image/components/img.tsx @@ -12,21 +12,25 @@ import { css } from '@emotion/react'; import { sizes } from '../styles'; export interface Props extends ImgHTMLAttributes { - hidden: boolean; size?: EuiImageSize; observerRef: (el: null | HTMLImageElement) => void; } export const Img = React.forwardRef( - ({ observerRef, src, hidden, size, ...rest }, ref) => { + ({ observerRef, src, size, ...rest }, ref) => { const { euiTheme } = useEuiTheme(); const styles = [ css` transition: opacity ${euiTheme.animation.extraFast}; `, - hidden + !src ? css` visibility: hidden; + position: absolute; // ensure that empty img tag occupies full container + top: 0; + right: 0; + bottom: 0; + left: 0; ` : undefined, size ? sizes[size] : undefined, diff --git a/x-pack/plugins/files/public/components/image/image.tsx b/x-pack/plugins/files/public/components/image/image.tsx index b83739d180c94..e353fced3ec3e 100644 --- a/x-pack/plugins/files/public/components/image/image.tsx +++ b/x-pack/plugins/files/public/components/image/image.tsx @@ -32,15 +32,6 @@ export interface Props extends ImgHTMLAttributes { * Emits when the image first becomes visible */ onFirstVisible?: () => void; - - /** - * As an optimisation images are only loaded when they are visible. - * This setting overrides this behavior and loads an image as soon as the - * component mounts. - * - * @default true - */ - lazy?: boolean; } /** @@ -55,33 +46,18 @@ export interface Props extends ImgHTMLAttributes { */ export const Image = React.forwardRef( ( - { - src, - alt, - onFirstVisible, - onLoad, - onError, - meta, - wrapperProps, - size = 'original', - lazy = true, - ...rest - }, + { src, alt, onFirstVisible, onLoad, onError, meta, wrapperProps, size = 'original', ...rest }, ref ) => { const [isLoaded, setIsLoaded] = useState(false); const [blurDelayExpired, setBlurDelayExpired] = useState(false); const { isVisible, ref: observerRef } = useViewportObserver({ onFirstVisible }); - const loadImage = lazy ? isVisible : true; - useEffect(() => { - let unmounted = false; const id = window.setTimeout(() => { - if (!unmounted) setBlurDelayExpired(true); + setBlurDelayExpired(true); }, 200); return () => { - unmounted = true; window.clearTimeout(id); }; }, []); @@ -112,8 +88,7 @@ export const Image = React.forwardRef( observerRef={observerRef} ref={ref} size={size} - hidden={!loadImage} - src={loadImage ? src : undefined} + src={isVisible ? src : undefined} alt={alt} onLoad={(ev) => { setIsLoaded(true); diff --git a/x-pack/plugins/files/server/feature.ts b/x-pack/plugins/files/server/feature.ts new file mode 100644 index 0000000000000..1685e95cc9fa6 --- /dev/null +++ b/x-pack/plugins/files/server/feature.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 { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; +import { KibanaFeatureConfig } from '@kbn/features-plugin/common'; +import { i18n } from '@kbn/i18n'; +import { PLUGIN_ID } from '../common'; +import { FILES_MANAGE_PRIVILEGE } from '../common/constants'; +import { hiddenTypes } from './saved_objects'; + +// TODO: This should be registered once we have a management section for files content +export const filesFeature: KibanaFeatureConfig = { + id: PLUGIN_ID, + name: i18n.translate('xpack.files.featureRegistry.filesFeatureName', { + defaultMessage: 'Files', + }), + minimumLicense: 'basic', + order: 10000, + category: DEFAULT_APP_CATEGORIES.management, + app: [PLUGIN_ID], + privilegesTooltip: i18n.translate('xpack.files.featureRegistry.filesPrivilegesTooltip', { + defaultMessage: 'Provide access to files across all apps', + }), + privileges: { + all: { + app: [PLUGIN_ID], + savedObject: { + all: hiddenTypes, + read: hiddenTypes, + }, + ui: [], + api: [FILES_MANAGE_PRIVILEGE], + }, + read: { + app: [PLUGIN_ID], + savedObject: { + all: hiddenTypes, + read: hiddenTypes, + }, + ui: [], + }, + }, +}; diff --git a/x-pack/plugins/files/server/routes/find.ts b/x-pack/plugins/files/server/routes/find.ts index 4f5a6da46b455..9ec5ab681cb66 100644 --- a/x-pack/plugins/files/server/routes/find.ts +++ b/x-pack/plugins/files/server/routes/find.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import type { CreateHandler, FilesRouter } from './types'; import { FileJSON } from '../../common'; +import { FILES_MANAGE_PRIVILEGE } from '../../common/constants'; import { FILES_API_ROUTES, CreateRouteDefinition } from './api_routes'; const method = 'post' as const; @@ -63,16 +64,14 @@ const handler: CreateHandler = async ({ files }, req, res) => { }); }; -// TODO: Find out whether we want to add stricter access controls to this route. -// Currently this is giving read-access to all files which bypasses the -// security we set up on a per route level for the "getById" and "list" endpoints. -// Alternatively, we can remove the access controls on the "file kind" endpoints -// or remove them entirely. export function register(router: FilesRouter) { router[method]( { path: FILES_API_ROUTES.find, validate: { ...rt }, + options: { + tags: [`access:${FILES_MANAGE_PRIVILEGE}`], + }, }, handler ); diff --git a/x-pack/plugins/files/server/routes/metrics.ts b/x-pack/plugins/files/server/routes/metrics.ts index eb1d0ae39b9a1..9ae898e17bb87 100644 --- a/x-pack/plugins/files/server/routes/metrics.ts +++ b/x-pack/plugins/files/server/routes/metrics.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FILES_MANAGE_PRIVILEGE } from '../../common/constants'; import type { FilesRouter } from './types'; import { FilesMetrics } from '../../common'; @@ -27,6 +28,9 @@ export function register(router: FilesRouter) { { path: FILES_API_ROUTES.metrics, validate: {}, + options: { + tags: [`access:${FILES_MANAGE_PRIVILEGE}`], + }, }, handler ); diff --git a/x-pack/plugins/fleet/.storybook/smoke.test.tsx b/x-pack/plugins/fleet/.storybook/smoke.test.tsx index 1fca60a1af4a4..a3984a42a5ab2 100644 --- a/x-pack/plugins/fleet/.storybook/smoke.test.tsx +++ b/x-pack/plugins/fleet/.storybook/smoke.test.tsx @@ -11,14 +11,16 @@ import { act } from 'react-dom/test-utils'; import initStoryshots from '@storybook/addon-storyshots'; describe('Fleet Storybook Smoke', () => { - initStoryshots({ - configPath: __dirname, - framework: 'react', - test: async ({ story }) => { - const renderer = mount(createElement(story.render)); - // wait until the element will perform all renders and resolve all promises (lazy loading, especially) - await act(() => new Promise((resolve) => setTimeout(resolve, 0))); - expect(renderer.html()).not.toContain('euiErrorBoundary'); - }, + test('Init', async () => { + await initStoryshots({ + configPath: __dirname, + framework: 'react', + test: async ({ story }) => { + const renderer = mount(createElement(story.render)); + // wait until the element will perform all renders and resolve all promises (lazy loading, especially) + await act(() => new Promise((resolve) => setTimeout(resolve, 0))); + expect(renderer.html()).not.toContain('euiErrorBoundary'); + }, + }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_add_agent_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_add_agent_modal.tsx index b6d568971140a..18be0df355395 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_add_agent_modal.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_add_agent_modal.tsx @@ -51,7 +51,7 @@ export const PostInstallAddAgentModal: React.FunctionComponent<{

Elastic Agent, }} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.test.tsx index 98b1688308203..33503018b49a0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/index.test.tsx @@ -110,7 +110,7 @@ describe('agent_list_page', () => { totalInactive: 0, }, }); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { diff --git a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts index f05441f3db1ff..af6ae76a646b0 100644 --- a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts +++ b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts @@ -81,21 +81,12 @@ spec: - name: varlog mountPath: /var/log readOnly: true - - name: etc-kubernetes - mountPath: /hostfs/etc/kubernetes + - name: etc-full + mountPath: /hostfs/etc readOnly: true - name: var-lib mountPath: /hostfs/var/lib readOnly: true - - name: passwd - mountPath: /hostfs/etc/passwd - readOnly: true - - name: group - mountPath: /hostfs/etc/group - readOnly: true - - name: etcsysmd - mountPath: /hostfs/etc/systemd - readOnly: true volumes: - name: datastreams configMap: @@ -113,26 +104,15 @@ spec: - name: varlog hostPath: path: /var/log - # Needed for cloudbeat - - name: etc-kubernetes + # The following volumes are needed for Cloud Security Posture integration (cloudbeat) + # If you are not using this integration, then these volumes and the corresponding + # mounts can be removed. + - name: etc-full hostPath: - path: /etc/kubernetes - # Needed for cloudbeat + path: /etc - name: var-lib hostPath: path: /var/lib - # Needed for cloudbeat - - name: passwd - hostPath: - path: /etc/passwd - # Needed for cloudbeat - - name: group - hostPath: - path: /etc/group - # Needed for cloudbeat - - name: etcsysmd - hostPath: - path: /etc/systemd --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -367,21 +347,12 @@ spec: - name: varlog mountPath: /var/log readOnly: true - - name: etc-kubernetes - mountPath: /hostfs/etc/kubernetes + - name: etc-full + mountPath: /hostfs/etc readOnly: true - name: var-lib mountPath: /hostfs/var/lib readOnly: true - - name: passwd - mountPath: /hostfs/etc/passwd - readOnly: true - - name: group - mountPath: /hostfs/etc/group - readOnly: true - - name: etcsysmd - mountPath: /hostfs/etc/systemd - readOnly: true - name: etc-mid mountPath: /etc/machine-id readOnly: true @@ -398,26 +369,15 @@ spec: - name: varlog hostPath: path: /var/log - # Needed for cloudbeat - - name: etc-kubernetes + # The following volumes are needed for Cloud Security Posture integration (cloudbeat) + # If you are not using this integration, then these volumes and the corresponding + # mounts can be removed. + - name: etc-full hostPath: - path: /etc/kubernetes - # Needed for cloudbeat + path: /etc - name: var-lib hostPath: path: /var/lib - # Needed for cloudbeat - - name: passwd - hostPath: - path: /etc/passwd - # Needed for cloudbeat - - name: group - hostPath: - path: /etc/group - # Needed for cloudbeat - - name: etcsysmd - hostPath: - path: /etc/systemd # Mount /etc/machine-id from the host to determine host ID # Needed for Elastic Security integration - name: etc-mid diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 92ea60d290040..2cf665e0fc094 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -141,6 +141,7 @@ export async function installKibanaAssetsAndReferences({ pkgTitle, paths, installedPkg, + spaceId, }: { savedObjectsClient: SavedObjectsClientContract; savedObjectsImporter: Pick; @@ -151,6 +152,7 @@ export async function installKibanaAssetsAndReferences({ pkgTitle: string; paths: string[]; installedPkg?: SavedObject; + spaceId: string; }) { const kibanaAssets = await getKibanaAssets(paths); if (installedPkg) await deleteKibanaSavedObjectsAssets({ savedObjectsClient, installedPkg }); @@ -167,7 +169,6 @@ export async function installKibanaAssetsAndReferences({ pkgName, kibanaAssets, }); - await withPackageSpan('Create and assign package tags', () => tagKibanaAssets({ savedObjectTagAssignmentService, @@ -175,6 +176,7 @@ export async function installKibanaAssetsAndReferences({ kibanaAssets, pkgTitle, pkgName, + spaceId, }) ); diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts index 3c946217d36b4..d887631240175 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts @@ -11,18 +11,18 @@ describe('tagKibanaAssets', () => { updateTagAssignments: jest.fn(), } as any; const savedObjectTagClient = { - getAll: jest.fn(), + get: jest.fn(), create: jest.fn(), } as any; beforeEach(() => { savedObjectTagAssignmentService.updateTagAssignments.mockReset(); - savedObjectTagClient.getAll.mockReset(); + savedObjectTagClient.get.mockReset(); savedObjectTagClient.create.mockReset(); }); - it('should create Managed and System tags when tagKibanaAssets with System package', async () => { - savedObjectTagClient.getAll.mockResolvedValue([]); + it('should create Managed and System tags when tagKibanaAssets with System package when no tags exist', async () => { + savedObjectTagClient.get.mockRejectedValue(new Error('not found')); savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => Promise.resolve({ id: name.toLowerCase(), name }) ); @@ -34,6 +34,7 @@ describe('tagKibanaAssets', () => { kibanaAssets, pkgTitle: 'System', pkgName: 'system', + spaceId: 'default', }); expect(savedObjectTagClient.create).toHaveBeenCalledWith( @@ -42,7 +43,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#FFFFFF', }, - { id: 'managed', overwrite: true, refresh: false } + { id: 'fleet-managed-default', overwrite: true, refresh: false } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -50,10 +51,10 @@ describe('tagKibanaAssets', () => { description: '', color: '#FFFFFF', }, - { id: 'system', overwrite: true, refresh: false } + { id: 'fleet-pkg-system-default', overwrite: true, refresh: false } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ - tags: ['managed', 'system'], + tags: ['fleet-managed-default', 'fleet-pkg-system-default'], assign: kibanaAssets.dashboard, unassign: [], refresh: false, @@ -61,10 +62,7 @@ describe('tagKibanaAssets', () => { }); it('should only assign Managed and System tags when tags already exist', async () => { - savedObjectTagClient.getAll.mockResolvedValue([ - { id: 'managed', name: 'Managed' }, - { id: 'system', name: 'System' }, - ]); + savedObjectTagClient.get.mockResolvedValue({ name: '', color: '', description: '' }); const kibanaAssets = { dashboard: [{ id: 'dashboard1', type: 'dashboard' }] } as any; await tagKibanaAssets({ @@ -73,11 +71,12 @@ describe('tagKibanaAssets', () => { kibanaAssets, pkgTitle: 'System', pkgName: 'system', + spaceId: 'default', }); expect(savedObjectTagClient.create).not.toHaveBeenCalled(); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ - tags: ['managed', 'system'], + tags: ['fleet-managed-default', 'fleet-pkg-system-default'], assign: kibanaAssets.dashboard, unassign: [], refresh: false, @@ -85,7 +84,7 @@ describe('tagKibanaAssets', () => { }); it('should skip non taggable asset types', async () => { - savedObjectTagClient.getAll.mockResolvedValue([]); + savedObjectTagClient.get.mockRejectedValue(new Error('tag not found')); savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => Promise.resolve({ id: name.toLowerCase(), name }) ); @@ -104,10 +103,11 @@ describe('tagKibanaAssets', () => { kibanaAssets, pkgTitle: 'System', pkgName: 'system', + spaceId: 'default', }); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ - tags: ['managed', 'system'], + tags: ['fleet-managed-default', 'fleet-pkg-system-default'], assign: [ ...kibanaAssets.dashboard, ...kibanaAssets.search, @@ -129,8 +129,132 @@ describe('tagKibanaAssets', () => { kibanaAssets, pkgTitle: 'System', pkgName: 'system', + spaceId: 'default', }); expect(savedObjectTagAssignmentService.updateTagAssignments).not.toHaveBeenCalled(); }); + + it('should use legacy managed tag if it exists', async () => { + savedObjectTagClient.get.mockImplementation(async (id: string) => { + if (id === 'managed') return { name: 'managed', description: '', color: '' }; + + throw new Error('not found'); + }); + + savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => + Promise.resolve({ id: name.toLowerCase(), name }) + ); + const kibanaAssets = { dashboard: [{ id: 'dashboard1', type: 'dashboard' }] } as any; + + await tagKibanaAssets({ + savedObjectTagAssignmentService, + savedObjectTagClient, + kibanaAssets, + pkgTitle: 'System', + pkgName: 'system', + spaceId: 'default', + }); + + expect(savedObjectTagClient.create).not.toHaveBeenCalledWith( + { + name: 'Managed', + description: '', + color: '#FFFFFF', + }, + { id: 'fleet-managed-default', overwrite: true, refresh: false } + ); + + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + name: 'System', + description: '', + color: '#FFFFFF', + }, + { id: 'fleet-pkg-system-default', overwrite: true, refresh: false } + ); + expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ + tags: ['managed', 'fleet-pkg-system-default'], + assign: kibanaAssets.dashboard, + unassign: [], + refresh: false, + }); + }); + + it('should use legacy package tag if it exists', async () => { + savedObjectTagClient.get.mockImplementation(async (id: string) => { + if (id === 'system') return { name: 'system', description: '', color: '' }; + + throw new Error('not found'); + }); + + savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => + Promise.resolve({ id: name.toLowerCase(), name }) + ); + const kibanaAssets = { dashboard: [{ id: 'dashboard1', type: 'dashboard' }] } as any; + + await tagKibanaAssets({ + savedObjectTagAssignmentService, + savedObjectTagClient, + kibanaAssets, + pkgTitle: 'System', + pkgName: 'system', + spaceId: 'default', + }); + + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + name: 'Managed', + description: '', + color: '#FFFFFF', + }, + { id: 'fleet-managed-default', overwrite: true, refresh: false } + ); + + expect(savedObjectTagClient.create).not.toHaveBeenCalledWith( + { + name: 'System', + description: '', + color: '#FFFFFF', + }, + { id: 'system', overwrite: true, refresh: false } + ); + expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ + tags: ['fleet-managed-default', 'system'], + assign: kibanaAssets.dashboard, + unassign: [], + refresh: false, + }); + }); + + it('should use both legacy tags if they exist', async () => { + savedObjectTagClient.get.mockImplementation(async (id: string) => { + if (id === 'managed') return { name: 'managed', description: '', color: '' }; + if (id === 'system') return { name: 'system', description: '', color: '' }; + + throw new Error('not found'); + }); + + savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => + Promise.resolve({ id: name.toLowerCase(), name }) + ); + const kibanaAssets = { dashboard: [{ id: 'dashboard1', type: 'dashboard' }] } as any; + + await tagKibanaAssets({ + savedObjectTagAssignmentService, + savedObjectTagClient, + kibanaAssets, + pkgTitle: 'System', + pkgName: 'system', + spaceId: 'default', + }); + + expect(savedObjectTagClient.create).not.toHaveBeenCalled(); + expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ + tags: ['managed', 'system'], + assign: kibanaAssets.dashboard, + unassign: [], + refresh: false, + }); + }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts index 842932d71359e..1d61c3c908872 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts @@ -15,22 +15,45 @@ import { KibanaSavedObjectTypeMapping } from './install'; const TAG_COLOR = '#FFFFFF'; const MANAGED_TAG_NAME = 'Managed'; -const MANAGED_TAG_ID = 'managed'; - -export async function tagKibanaAssets({ - savedObjectTagAssignmentService, - savedObjectTagClient, - kibanaAssets, - pkgTitle, - pkgName, -}: { +const LEGACY_MANAGED_TAG_ID = 'managed'; + +const getManagedTagId = (spaceId: string) => `fleet-managed-${spaceId}`; +const getPackageTagId = (spaceId: string, pkgName: string) => `fleet-pkg-${pkgName}-${spaceId}`; +const getLegacyPackageTagId = (pkgName: string) => pkgName; + +interface TagAssetsParams { savedObjectTagAssignmentService: IAssignmentService; savedObjectTagClient: ITagsClient; kibanaAssets: Record; pkgTitle: string; pkgName: string; -}) { - const taggableAssets = Object.entries(kibanaAssets).flatMap(([assetType, assets]) => { + spaceId: string; +} + +export async function tagKibanaAssets(opts: TagAssetsParams) { + const { savedObjectTagAssignmentService, kibanaAssets } = opts; + const taggableAssets = getTaggableAssets(kibanaAssets); + + // no assets to tag + if (taggableAssets.length === 0) { + return; + } + + const [managedTagId, packageTagId] = await Promise.all([ + ensureManagedTag(opts), + ensurePackageTag(opts), + ]); + + await savedObjectTagAssignmentService.updateTagAssignments({ + tags: [managedTagId, packageTagId], + assign: taggableAssets, + unassign: [], + refresh: false, + }); +} + +function getTaggableAssets(kibanaAssets: TagAssetsParams['kibanaAssets']) { + return Object.entries(kibanaAssets).flatMap(([assetType, assets]) => { if (!taggableTypes.includes(KibanaSavedObjectTypeMapping[assetType as KibanaAssetType])) { return []; } @@ -41,41 +64,57 @@ export async function tagKibanaAssets({ return assets; }); +} - // no assets to tag - if (taggableAssets.length === 0) { - return; - } +async function ensureManagedTag( + opts: Pick +): Promise { + const { spaceId, savedObjectTagClient } = opts; - const allTags = await savedObjectTagClient.getAll(); - let managedTag = allTags.find((tag) => tag.name === MANAGED_TAG_NAME); - if (!managedTag) { - managedTag = await savedObjectTagClient.create( - { - name: MANAGED_TAG_NAME, - description: '', - color: TAG_COLOR, - }, - { id: MANAGED_TAG_ID, overwrite: true, refresh: false } - ); - } + const managedTagId = getManagedTagId(spaceId); + const managedTag = await savedObjectTagClient.get(managedTagId).catch(() => {}); - let packageTag = allTags.find((tag) => tag.name === pkgTitle); - if (!packageTag) { - packageTag = await savedObjectTagClient.create( - { - name: pkgTitle, - description: '', - color: TAG_COLOR, - }, - { id: pkgName, overwrite: true, refresh: false } - ); - } + if (managedTag) return managedTagId; - await savedObjectTagAssignmentService.updateTagAssignments({ - tags: [managedTag.id, packageTag.id], - assign: taggableAssets, - unassign: [], - refresh: false, - }); + const legacyManagedTag = await savedObjectTagClient.get(LEGACY_MANAGED_TAG_ID).catch(() => {}); + + if (legacyManagedTag) return LEGACY_MANAGED_TAG_ID; + + await savedObjectTagClient.create( + { + name: MANAGED_TAG_NAME, + description: '', + color: TAG_COLOR, + }, + { id: managedTagId, overwrite: true, refresh: false } + ); + + return managedTagId; +} + +async function ensurePackageTag( + opts: Pick +): Promise { + const { spaceId, savedObjectTagClient, pkgName, pkgTitle } = opts; + + const packageTagId = getPackageTagId(spaceId, pkgName); + const packageTag = await savedObjectTagClient.get(packageTagId).catch(() => {}); + + if (packageTag) return packageTagId; + + const legacyPackageTagId = getLegacyPackageTagId(pkgName); + const legacyPackageTag = await savedObjectTagClient.get(legacyPackageTagId).catch(() => {}); + + if (legacyPackageTag) return legacyPackageTagId; + + await savedObjectTagClient.create( + { + name: pkgTitle, + description: '', + color: TAG_COLOR, + }, + { id: packageTagId, overwrite: true, refresh: false } + ); + + return packageTagId; } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 4ecec17560731..78683ecd07e0a 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -133,6 +133,7 @@ export async function _installPackage({ paths, installedPkg, logger, + spaceId, }) ); // Necessary to avoid async promise rejection warning diff --git a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts index 8b1529de93b3c..0ff64789d12ed 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts @@ -5,12 +5,9 @@ * 2.0. */ -import HttpProxyAgent from 'http-proxy-agent'; -import HttpsProxyAgent from 'https-proxy-agent'; -import type { - HttpsProxyAgentOptions, - HttpsProxyAgent as IHttpsProxyAgent, -} from 'https-proxy-agent'; +import { HttpProxyAgent } from 'http-proxy-agent'; +import { HttpsProxyAgent } from 'https-proxy-agent'; +import type { HttpsProxyAgentOptions } from 'https-proxy-agent'; import { appContextService } from '../..'; @@ -20,7 +17,7 @@ export interface RegistryProxySettings { proxyRejectUnauthorizedCertificates?: boolean; } -type ProxyAgent = IHttpsProxyAgent | HttpProxyAgent; +type ProxyAgent = HttpsProxyAgent | HttpProxyAgent; type GetProxyAgentParams = RegistryProxySettings & { targetUrl: string }; export function getRegistryProxyUrl(): string | undefined { @@ -30,11 +27,10 @@ export function getRegistryProxyUrl(): string | undefined { export function getProxyAgent(options: GetProxyAgentParams): ProxyAgent { const isHttps = options.targetUrl.startsWith('https:'); - const agentOptions = isHttps && getProxyAgentOptions(options); + const agentOptions = isHttps ? getProxyAgentOptions(options) : options.proxyUrl; const agent: ProxyAgent = isHttps - ? // @ts-expect-error ts(7009) HttpsProxyAgent isn't a class so TS complains about using `new` - new HttpsProxyAgent(agentOptions) - : new HttpProxyAgent(options.proxyUrl); + ? new HttpsProxyAgent(agentOptions) + : new HttpProxyAgent(agentOptions); return agent; } diff --git a/x-pack/plugins/fleet/server/services/package_policies/package_policy_name_helper.ts b/x-pack/plugins/fleet/server/services/package_policies/package_policy_name_helper.ts index c712ccc06ad92..90db39a3e03b0 100644 --- a/x-pack/plugins/fleet/server/services/package_policies/package_policy_name_helper.ts +++ b/x-pack/plugins/fleet/server/services/package_policies/package_policy_name_helper.ts @@ -39,20 +39,23 @@ export async function incrementPackagePolicyCopyName( // find all pacakge policies starting with the same name and increment the name const packagePolicyData = await packagePolicyService.list(soClient, { perPage: SO_SEARCH_LIMIT, - kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: ${packageName}*`, + // split package name on first space as KQL do not support wildcard and space + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: ${packageName.split(' ')[0]}*`, }); const maxVersion = packagePolicyData.items.length > 0 ? Math.max( - ...packagePolicyData.items.map((item) => { - const matches = item.name.match(/^(.*)\s\(copy\s?([0-9]*)\)$/); - if (matches) { - return parseInt(matches[2], 10) || 1; - } + ...packagePolicyData.items + .filter((item) => item.name.startsWith(packageName)) + .map((item) => { + const matches = item.name.match(/^(.*)\s\(copy\s?([0-9]*)\)$/); + if (matches) { + return parseInt(matches[2], 10) || 1; + } - return 0; - }) + return 0; + }) ) : 0; diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx index 78f38087b9ad1..2bd37e0448b6c 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx @@ -42,7 +42,7 @@ const createResult = (result: Result): GlobalSearchResult => { const createBatch = (...results: Result[]): GlobalSearchBatchedResults => ({ results: results.map(createResult), }); -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); describe('SearchBar', () => { let searchService: ReturnType; diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/edit_warning.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/edit_warning.test.ts index 98d6078da031c..39417219cddb9 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/edit_warning.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/edit_warning.test.ts @@ -16,7 +16,7 @@ describe(' edit warning', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/frozen_phase.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/frozen_phase.test.ts index ffe11133be7fd..5b08b4225916b 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/frozen_phase.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/frozen_phase.test.ts @@ -17,7 +17,7 @@ describe(' frozen phase', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cloud_aware_behavior.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cloud_aware_behavior.test.ts index 75db772ec0926..be83028c81b2f 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cloud_aware_behavior.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cloud_aware_behavior.test.ts @@ -18,7 +18,7 @@ describe(' node allocation cloud-aware behavior', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cold_phase.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cold_phase.test.ts index 63382de45f414..217a6264f5745 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cold_phase.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/cold_phase.test.ts @@ -14,7 +14,7 @@ describe(' node allocation in the cold phase', () => { const { httpSetup, setDelayResponse, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/general_behavior.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/general_behavior.test.ts index 4830cee8ee237..e9f970fbba207 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/general_behavior.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/general_behavior.test.ts @@ -24,7 +24,7 @@ describe(' node allocation general behavior', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/warm_phase.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/warm_phase.test.ts index 6f96aaf07da1b..df6e409550be9 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/warm_phase.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/node_allocation/warm_phase.test.ts @@ -14,7 +14,7 @@ describe(' node allocation in the warm phase', () => { const { httpSetup, setDelayResponse, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/request_flyout.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/request_flyout.test.ts index 61dda6fa65efb..30873b54548eb 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/request_flyout.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/features/request_flyout.test.ts @@ -15,7 +15,7 @@ describe(' request flyout', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/cold_phase_validation.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/cold_phase_validation.test.ts index e75d2cb72ab28..cee0af407442e 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/cold_phase_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/cold_phase_validation.test.ts @@ -15,7 +15,7 @@ describe(' cold phase validation', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/error_indicators.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/error_indicators.test.ts index bd4a2caec0be5..2503b32f0506a 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/error_indicators.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/error_indicators.test.ts @@ -14,7 +14,7 @@ describe(' error indicators', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/hot_phase_validation.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/hot_phase_validation.test.ts index 71f83a59360d6..54683f638c746 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/hot_phase_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/hot_phase_validation.test.ts @@ -16,7 +16,7 @@ describe(' hot phase validation', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/policy_name_validation.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/policy_name_validation.test.ts index c530f73a66c11..19ee23142cd92 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/policy_name_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/policy_name_validation.test.ts @@ -17,7 +17,7 @@ describe(' policy name validation', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/timing.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/timing.test.ts index 5838f04ba70e9..08790cf23bf95 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/timing.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/timing.test.ts @@ -18,7 +18,7 @@ describe(' timing validation', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/warm_phase_validation.test.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/warm_phase_validation.test.ts index 47917b1f8e3d7..6fb079819ec36 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/warm_phase_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/form_validation/warm_phase_validation.test.ts @@ -15,7 +15,7 @@ describe(' warm phase validation', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx index 861b1041a4f14..99277bb4cc4b6 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx @@ -48,7 +48,7 @@ describe('', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); httpRequestsMockHelpers.setLoadTelemetryResponse({}); httpRequestsMockHelpers.setLoadComponentTemplatesResponse([]); httpRequestsMockHelpers.setLoadTemplateResponse(templateToClone.name, templateToClone); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx index 6813398a34ae0..ca42777532acc 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx @@ -80,7 +80,7 @@ describe('', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); httpRequestsMockHelpers.setLoadComponentTemplatesResponse(componentTemplates); httpRequestsMockHelpers.setLoadNodesPluginsResponse([]); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx index 4b94cb92c83d0..a99b5476a766f 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx @@ -52,7 +52,7 @@ describe('', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); httpRequestsMockHelpers.setLoadComponentTemplatesResponse([]); }); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/date_range_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/date_range_datatype.test.tsx index 60114223bef0d..1b752807ba1c9 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/date_range_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/date_range_datatype.test.tsx @@ -29,7 +29,7 @@ describe('Mappings editor: date range datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/other_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/other_datatype.test.tsx index 81ca155b022b1..58d063cc658cc 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/other_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/other_datatype.test.tsx @@ -21,7 +21,7 @@ describe('Mappings editor: other datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/point_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/point_datatype.test.tsx index 8c235f2d2d9e9..c35d6c231186d 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/point_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/point_datatype.test.tsx @@ -28,7 +28,7 @@ describe('Mappings editor: point datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/scaled_float_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/scaled_float_datatype.test.tsx index 17e7317e098cc..bbd0afa495e48 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/scaled_float_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/scaled_float_datatype.test.tsx @@ -31,7 +31,7 @@ describe('Mappings editor: scaled float datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/shape_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/shape_datatype.test.tsx index 94aea2a3b13af..9724a81d673bf 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/shape_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/shape_datatype.test.tsx @@ -29,7 +29,7 @@ describe('Mappings editor: shape datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx index db8678478aa3d..38fd47476e931 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx @@ -34,7 +34,7 @@ describe('Mappings editor: text datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/version_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/version_datatype.test.tsx index 5f638ebb31a43..6a61d9bac058b 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/version_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/version_datatype.test.tsx @@ -26,7 +26,7 @@ describe('Mappings editor: version datatype', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/edit_field.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/edit_field.test.tsx index 4440f54f1034b..7403be97c6644 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/edit_field.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/edit_field.test.tsx @@ -21,7 +21,7 @@ describe('Mappings editor: edit field', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mapped_fields.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mapped_fields.test.tsx index eb219503424b3..fe32e3b6099f0 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mapped_fields.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mapped_fields.test.tsx @@ -14,7 +14,7 @@ const onChangeHandler = jest.fn(); describe('Mappings editor: mapped fields', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx index 9b4f31f3dfc16..c296361f3685b 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx @@ -21,7 +21,7 @@ describe('Mappings editor: core', () => { let testBed: MappingsEditorTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/runtime_fields.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/runtime_fields.test.tsx index 76e5dcda8fc44..d1b85685588d0 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/runtime_fields.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/runtime_fields.test.tsx @@ -20,7 +20,7 @@ describe('Mappings editor: runtime fields', () => { let getMappingsEditorData = getMappingsEditorDataFactory(onChangeHandler); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx index f81f80faca73e..d045c594f0ee6 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiBasicTable } from '@elastic/eui'; +import { EuiInMemoryTable } from '@elastic/eui'; import type { SnapshotNode } from '../../../../../common/http_api'; import { HostsTableColumns } from './hosts_table_columns'; import { useHostTable } from '../hooks/use_host_table'; @@ -18,11 +18,5 @@ interface Props { export const HostsTable: React.FunctionComponent = ({ nodes }) => { const items = useHostTable(nodes); - return ( - - ); + return ; }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx index 7bd8184b0e464..04d035b5fb7eb 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx @@ -9,13 +9,14 @@ import { EuiBasicTableColumn } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiText } from '@elastic/eui'; +import type { SnapshotNodeMetric } from '../../../../../common/http_api'; import { scaleUpPercentage } from '../../../../components/infrastructure_node_metrics_tables/shared/hooks'; -import type { SnapshotNodeMetric } from '../../../../../common/http_api/snapshot_api'; import { NumberCell } from '../../../../components/infrastructure_node_metrics_tables/shared/components'; interface HostNodeRow extends HostMetics { - os?: string | null | undefined; - servicesOnHost?: number | null | undefined; + os?: string | null; + servicesOnHost?: number | null; + name: string; } export interface HostMetics { @@ -31,7 +32,8 @@ export const HostsTableColumns: Array> = [ name: i18n.translate('xpack.infra.hostsTable.nameColumnHeader', { defaultMessage: 'Name', }), - field: 'label', + field: 'name', + sortable: true, truncateText: true, textOnly: true, render: (name: string) => {name}, @@ -41,59 +43,63 @@ export const HostsTableColumns: Array> = [ defaultMessage: 'Operating System', }), field: 'os', - render: (os: string) => {os ?? '-'}, + sortable: true, + render: (os: string) => {os}, }, { name: i18n.translate('xpack.infra.hostsTable.numberOfCpusColumnHeader', { defaultMessage: '# of CPUs', }), - field: 'cpuCores', - render: (cpuCores: { value: number }) => , + field: 'cpuCores.value', + sortable: true, + render: (value: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.diskLatencyColumnHeader', { defaultMessage: 'Disk Latency', }), field: 'diskLatency', + sortable: true, render: (ds: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.averageTxColumnHeader', { defaultMessage: 'TX (avg.)', }), - field: 'tx', - render: (tx: { avg: number }) => , + field: 'tx.avg', + sortable: true, + render: (avg: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.averageRxColumnHeader', { defaultMessage: 'RX (avg.)', }), - field: 'rx', - render: (rx: { avg: number }) => , + field: 'rx.avg', + sortable: true, + render: (avg: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.averageMemoryTotalColumnHeader', { defaultMessage: 'Memory total (avg.)', }), - field: 'memoryTotal', - render: (memoryTotal: { avg: number }) => ( - - ), + field: 'memoryTotal.avg', + sortable: true, + render: (avg: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.servicesOnHostColumnHeader', { defaultMessage: 'Services on Host', }), field: 'servicesOnHost', + sortable: true, render: (servicesOnHost: number) => , }, { name: i18n.translate('xpack.infra.hostsTable.averageMemoryUsageColumnHeader', { defaultMessage: 'Memory usage (avg.)', }), - field: 'memory', - render: (memory: { avg: number }) => ( - - ), + field: 'memory.avg', + sortable: true, + render: (avg: number) => , }, ]; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts index e0d26413f0453..81b0e93f10121 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts @@ -70,6 +70,8 @@ describe('useHostTable hook', () => { const items = [ { + name: 'host-0', + os: '-', rx: { name: 'rx', avg: 252456.92916666667, @@ -91,11 +93,10 @@ describe('useHostTable hook', () => { avg: 34359.738368, }, - value: 'host-0', - label: 'host-0', - os: null, }, { + name: 'host-1', + os: 'macOS', rx: { name: 'rx', avg: 95.86339715321859, @@ -116,10 +117,6 @@ describe('useHostTable hook', () => { name: 'memoryTotal', avg: 9.194304, }, - value: 'host-1', - label: 'host-1', - ip: '243.86.94.22', - os: 'macOS', }, ]; const result = renderHook(() => useHostTable(nodes)); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts index 4c604b2a27217..32eed5e54ce6b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { last } from 'lodash'; import { useMemo } from 'react'; import type { SnapshotNode, SnapshotNodeMetric } from '../../../../../common/http_api'; import { HostMetics } from '../components/hosts_table_columns'; @@ -13,9 +12,10 @@ import { HostMetics } from '../components/hosts_table_columns'; type MappedMetrics = Record; export const useHostTable = (nodes: SnapshotNode[]) => { - const items: MappedMetrics[] = useMemo(() => { - return nodes.map(({ metrics, path }) => ({ - ...last(path), + const items = useMemo(() => { + return nodes.map(({ metrics, path, name }) => ({ + name, + os: path.at(-1)?.os ?? '-', ...metrics.reduce((data, metric) => { data[metric.name as keyof HostMetics] = metric; return data; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx index 25aa168ca8dc0..5ab4a062d7fc9 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx @@ -50,15 +50,15 @@ export const HostsContent: React.FunctionComponent = () => { [], 'host', sourceId, - 1666081614879, // currentTime. need to add support for TimeRange? + 1666710279338, // currentTime. need to add support for TimeRange? '', '', true, { - from: 1666081614879, // dynamic time range needs to be supported + from: 1666710279338, // dynamic time range needs to be supported interval: '1m', lookbackSize: 5, - to: 1666082814879, + to: 1666711479338, } ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx index c5daa1db2ac07..9e31c71e0f275 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx @@ -39,7 +39,7 @@ describe('Pipeline Editor', () => { let testBed: SetupResult; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/append.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/append.test.tsx index f35e05b800f14..632dc824dbd1a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/append.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/append.test.tsx @@ -17,7 +17,7 @@ describe('Processor: Append', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/bytes.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/bytes.test.tsx index d4ac176d6aaf5..44acef642caa5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/bytes.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/bytes.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Bytes', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx index 00153471ea65e..01b25bc508bcc 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Circle', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/common_processor_fields.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/common_processor_fields.test.tsx index ebffd5adf78c1..45781e15eca59 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/common_processor_fields.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/common_processor_fields.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Common Fields For All Processors', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/community_id.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/community_id.test.tsx index e571474576ff2..4ed8ff5b05285 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/community_id.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/community_id.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Community id', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx index 3090e59b32e0b..d328bb6759b2f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx @@ -26,7 +26,7 @@ describe('Processor: Convert', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/csv.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/csv.test.tsx index 6414976b56f9a..c3237c1d23259 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/csv.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/csv.test.tsx @@ -29,7 +29,7 @@ describe('Processor: CSV', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date.test.tsx index 22666ebbe2a98..fa1edd6d6cb51 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Date', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date_index.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date_index.test.tsx index b9e990f36c15b..74a49b11821ee 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date_index.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/date_index.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Date Index Name', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/dot_expander.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/dot_expander.test.tsx index 7ebad2de01a92..c95a254870418 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/dot_expander.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/dot_expander.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Dot Expander', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fail.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fail.test.tsx index 9b8148bd0dffd..94a7bc65e65cc 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fail.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fail.test.tsx @@ -15,7 +15,7 @@ describe('Processor: Fail', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fingerprint.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fingerprint.test.tsx index 49d7937fab002..b5b5fa9c9e1d3 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fingerprint.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/fingerprint.test.tsx @@ -28,7 +28,7 @@ describe('Processor: Fingerprint', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts index 90ea4ed1a0105..89efc203c0c53 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts @@ -17,7 +17,7 @@ describe('Processor: Grok', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // disable all react-beautiful-dnd development warnings (window as any)['__react-beautiful-dnd-disable-dev-warnings'] = true; }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx index 4f92aec06efd3..330b651b5b515 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx @@ -30,7 +30,7 @@ describe('Processor: Network Direction', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor_form.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor_form.test.tsx index b2e2fb81f2c86..1b89dbe835a96 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor_form.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor_form.test.tsx @@ -14,7 +14,7 @@ describe('Processor: Bytes', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/registered_domain.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/registered_domain.test.tsx index dcf332912a94b..b4fafe6a47572 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/registered_domain.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/registered_domain.test.tsx @@ -24,7 +24,7 @@ describe('Processor: Registered Domain', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/set.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/set.test.tsx index ebfa678648904..d90c34ee10c8a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/set.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/set.test.tsx @@ -16,7 +16,7 @@ describe('Processor: Set', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/uri_parts.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/uri_parts.test.tsx index 9062fcc02f7f8..e59dba0aecddf 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/uri_parts.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/uri_parts.test.tsx @@ -22,7 +22,7 @@ describe('Processor: URI parts', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx index ed778aa1cc1f3..e2e083715c88e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/user_agent.test.tsx @@ -27,7 +27,7 @@ describe('Processor: User Agent', () => { const { httpSetup } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx index b15172185cff2..5bd7d1d30aea5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx @@ -46,7 +46,7 @@ describe('Test pipeline', () => { }; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts index 7c575241ba30b..fdaf1f51c644b 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts @@ -1789,9 +1789,7 @@ describe('IndexPattern Data Source', () => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/143908 - // FLAKY: https://github.com/elastic/kibana/issues/143907 - describe.skip('#clearLayer', () => { + describe('#clearLayer', () => { it('should clear a layer', () => { const state = { layers: { @@ -1817,6 +1815,7 @@ describe('IndexPattern Data Source', () => { columnOrder: [], columns: {}, linkToLayers: ['some-layer'], + sampling: 1, }, }, }, @@ -1845,7 +1844,7 @@ describe('IndexPattern Data Source', () => { newState: { ...state, layers: { - first: state.layers.first, + first: { ...state.layers.first, linkToLayers: undefined, sampling: 1 }, }, }, }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx index 0d292b7a3a26e..60c1a0cdf0f5d 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx @@ -235,7 +235,7 @@ export const countOperation: OperationDefinition { { indexPattern: {} } ); }); + + test('should pass over advanced parameters as global params for formula', () => { + const baseLayer = getBaseLayer(); + + publicApiHelper.insertOrReplaceFormulaColumn( + 'col', + { + formula: 'count()', + timeScale: 'd', + filter: { query: 'myField: *', language: 'kuery' }, + reducedTimeRange: '30s', + }, + baseLayer, + dataView + ); + + expect(insertOrReplaceFormulaColumn).toHaveBeenCalledWith( + 'col', + { + customLabel: false, + dataType: 'number', + isBucketed: false, + label: 'count()', + operationType: 'formula', + params: { formula: 'count()', format: undefined }, + filter: { + language: 'kuery', + query: 'myField: *', + }, + timeScale: 'd', + reducedTimeRange: '30s', + references: [], + }, + { + columnOrder: ['col1'], + columns: { + col1: { + dataType: 'date', + isBucketed: true, + label: '@timestamp', + operationType: 'date_histogram', + params: { interval: 'auto' }, + scale: 'interval', + }, + }, + indexPatternId: undefined, + }, + { indexPattern: {} } + ); + }); }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts index ab17fd81e84ef..56469d61ad8f3 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts @@ -10,6 +10,7 @@ import { Query } from '@kbn/es-query'; import { convertDataViewIntoLensIndexPattern } from '../../../../../data_views_service/loader'; import type { IndexPattern } from '../../../../../types'; import type { PersistedIndexPatternLayer } from '../../../types'; +import type { TimeScaleUnit } from '../../../../../../common/expressions'; import { insertOrReplaceFormulaColumn } from './parse'; @@ -33,6 +34,8 @@ export interface FormulaPublicApi { formula: string; label?: string; filter?: Query; + reducedTimeRange?: string; + timeScale?: TimeScaleUnit; format?: { id: string; params?: { @@ -60,7 +63,12 @@ export const createFormulaPublicApi = (): FormulaPublicApi => { }; return { - insertOrReplaceFormulaColumn: (id, { formula, label, format, filter }, layer, dataView) => { + insertOrReplaceFormulaColumn: ( + id, + { formula, label, format, filter, reducedTimeRange, timeScale }, + layer, + dataView + ) => { const indexPattern = getCachedLensIndexPattern(dataView); return insertOrReplaceFormulaColumn( @@ -73,6 +81,8 @@ export const createFormulaPublicApi = (): FormulaPublicApi => { references: [], isBucketed: false, filter, + reducedTimeRange, + timeScale, params: { formula, format, diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx index e8c8c54c1cefe..bb15831a31854 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx @@ -318,7 +318,7 @@ export const averageOperation = buildMetricOperation({ quickFunctionDocumentation: i18n.translate( 'xpack.lens.indexPattern.avg.quickFunctionDescription', { - defaultMessage: 'The average value of a number field.', + defaultMessage: 'The mean value of a set of number fields.', } ), }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.test.tsx index d0dd9f6458612..d238fd16b8932 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.test.tsx @@ -187,7 +187,7 @@ describe('ranges', () => { } beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); beforeEach(() => { diff --git a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx index af680fbc27160..b8c59712b096f 100644 --- a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx +++ b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx @@ -19,7 +19,7 @@ import { import { act } from 'react-dom/test-utils'; import { DropType } from '../types'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); const dataTransfer = { setData: jest.fn(), diff --git a/x-pack/plugins/lens/public/drag_drop/providers/providers.test.tsx b/x-pack/plugins/lens/public/drag_drop/providers/providers.test.tsx index a8312cc927451..8bbe30e29cb82 100644 --- a/x-pack/plugins/lens/public/drag_drop/providers/providers.test.tsx +++ b/x-pack/plugins/lens/public/drag_drop/providers/providers.test.tsx @@ -9,7 +9,7 @@ import React, { useContext } from 'react'; import { mount } from 'enzyme'; import { RootDragDropProvider, DragContext } from '.'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); describe('RootDragDropProvider', () => { test('reuses contexts for each render', () => { diff --git a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.test.ts b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.test.ts new file mode 100644 index 0000000000000..19aa122aa9f95 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants'; +import { LayerGroup } from './layer_group'; +import { ILayer } from '../layer'; + +describe('getMinZoom', () => { + test('should return MIN_ZOOM when there are no children', async () => { + const layerGroup = new LayerGroup({ layerDescriptor: LayerGroup.createDescriptor({}) }); + expect(layerGroup.getMinZoom()).toBe(MIN_ZOOM); + }); + + test('should return smallest child.getMinZoom()', async () => { + const layerGroup = new LayerGroup({ layerDescriptor: LayerGroup.createDescriptor({}) }); + layerGroup.setChildren([ + { + getMinZoom: () => { + return 1; + }, + } as unknown as ILayer, + { + getMinZoom: () => { + return 4; + }, + } as unknown as ILayer, + ]); + expect(layerGroup.getMinZoom()).toBe(1); + }); +}); + +describe('getMaxZoom', () => { + test('should return MAX_ZOOM when there are no children', async () => { + const layerGroup = new LayerGroup({ layerDescriptor: LayerGroup.createDescriptor({}) }); + expect(layerGroup.getMaxZoom()).toBe(MAX_ZOOM); + }); + + test('should return largest child.getMaxZoom()', async () => { + const layerGroup = new LayerGroup({ layerDescriptor: LayerGroup.createDescriptor({}) }); + layerGroup.setChildren([ + { + getMaxZoom: () => { + return 18; + }, + } as unknown as ILayer, + { + getMaxZoom: () => { + return 20; + }, + } as unknown as ILayer, + ]); + expect(layerGroup.getMaxZoom()).toBe(20); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx index c0e3c4ee56402..c1a2a2964a315 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx @@ -207,20 +207,34 @@ export class LayerGroup implements ILayer { return zoom >= this.getMinZoom() && zoom <= this.getMaxZoom(); } + /* + * Returns smallest min from children or MIN_ZOOM when there are no children + */ getMinZoom(): number { - let min = MIN_ZOOM; + let min: number | undefined; this._children.forEach((child) => { - min = Math.max(min, child.getMinZoom()); + if (min !== undefined) { + min = Math.min(min, child.getMinZoom()); + } else { + min = child.getMinZoom(); + } }); - return min; + return min !== undefined ? min : MIN_ZOOM; } + /* + * Returns largest max from children or MAX_ZOOM when there are no children + */ getMaxZoom(): number { - let max = MAX_ZOOM; + let max: number | undefined; this._children.forEach((child) => { - max = Math.min(max, child.getMaxZoom()); + if (max !== undefined) { + max = Math.max(max, child.getMaxZoom()); + } else { + max = child.getMaxZoom(); + } }); - return max; + return max !== undefined ? max : MAX_ZOOM; } getMinSourceZoom(): number { 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 cc16e408bf7bb..865ad53ebe3da 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 @@ -13,12 +13,17 @@ import { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { maplibregl } from '@kbn/mapbox-gl'; import type { Map as MapboxMap, MapOptions, MapMouseEvent } from '@kbn/mapbox-gl'; import { ResizeChecker } from '@kbn/kibana-utils-plugin/public'; +import { METRIC_TYPE } from '@kbn/analytics'; import { DrawFilterControl } from './draw_control/draw_filter_control'; import { ScaleControl } from './scale_control'; import { TooltipControl } from './tooltip_control'; import { clampToLatBounds, clampToLonBounds } from '../../../common/elasticsearch_util'; import { getInitialView } from './get_initial_view'; -import { getPreserveDrawingBuffer, isScreenshotMode } from '../../kibana_services'; +import { + getPreserveDrawingBuffer, + getUsageCollection, + isScreenshotMode, +} from '../../kibana_services'; import { ILayer } from '../../classes/layers/layer'; import { CustomIcon, @@ -28,6 +33,7 @@ import { Timeslice, } from '../../../common/descriptor_types'; import { + APP_ID, CUSTOM_ICON_SIZE, DECIMAL_DEGREES_PRECISION, MAKI_ICON_SIZE, @@ -149,6 +155,7 @@ export class MbMap extends Component { } async _createMbMapInstance(initialView: MapCenterAndZoom | null): Promise { + this._reportUsage(); return new Promise((resolve) => { const mbStyle = { version: 8 as 8, @@ -270,6 +277,24 @@ export class MbMap extends Component { }); } + _reportUsage() { + const usageCollector = getUsageCollection(); + if (!usageCollector) return; + + const webglSupport = maplibregl.supported(); + + usageCollector.reportUiCounter( + APP_ID, + METRIC_TYPE.LOADED, + webglSupport ? 'gl_webglSupported' : 'gl_webglNotSupported' + ); + + // Report low system performance or no hardware GPU + if (webglSupport && !maplibregl.supported({ failIfMajorPerformanceCaveat: true })) { + usageCollector.reportUiCounter(APP_ID, METRIC_TYPE.LOADED, 'gl_majorPerformanceCaveat'); + } + } + async _loadMakiSprites(mbMap: MapboxMap) { if (this._isMounted) { // Math.floor rounds values < 1 to 0. This occurs when browser is zoomed out diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/_layer_toc.scss b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/_layer_toc.scss index 868c120c31691..a3a03097acb06 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/_layer_toc.scss +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/_layer_toc.scss @@ -6,6 +6,10 @@ cursor: alias !important; } +.mapLayerToc-droppable-isCombining { + background-color: $euiColorEmptyShade !important; +} + .mapLayerToc-droppable-isDragging * { cursor: ns-resize !important; } \ No newline at end of file diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/layer_toc.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/layer_toc.tsx index f152d1686b3bd..54a5d13e7702d 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/layer_toc.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/layer_toc.tsx @@ -244,6 +244,10 @@ export class LayerTOC extends Component { dragHandleProps={draggableProvided.dragHandleProps} isDragging={draggableSnapshot.isDragging} isDraggingOver={droppableSnapshot.isDraggingOver} + isCombineLayer={ + this.state.combineLayer !== null && + this.state.combineLayer.getId() === layer.getId() + } /> ); }} diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss index 094d116b78623..959176547dfb2 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss @@ -62,6 +62,11 @@ pointer-events: none !important; } +.mapTocEntry-isCombineLayer { + transition: background-color $euiAnimSpeedExtraSlow ease; + background-color: transparentize($euiColorSuccess, .75); +} + .mapTocEntry-isSelected { background-color: tintOrShade($euiColorLightShade, 60%, 20%); } diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx index 72eb38f07257e..012c1e97ad528 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx @@ -49,6 +49,7 @@ export interface OwnProps { dragHandleProps?: DraggableProvidedDragHandleProps; isDragging?: boolean; isDraggingOver?: boolean; + isCombineLayer?: boolean; } type Props = ReduxStateProps & ReduxDispatchProps & OwnProps; @@ -314,6 +315,7 @@ export class TOCEntry extends Component { const classes = classNames('mapTocEntry', { 'mapTocEntry-isDragging': this.props.isDragging, 'mapTocEntry-isDraggingOver': this.props.isDraggingOver, + 'mapTocEntry-isCombineLayer': this.props.isCombineLayer, 'mapTocEntry-isSelected': this.props.layer.isPreviewLayer() || (this.props.selectedLayer && this.props.selectedLayer.getId() === this.props.layer.getId()), diff --git a/x-pack/plugins/ml/public/application/components/navigation_menu/date_picker_wrapper/date_picker_wrapper.test.tsx b/x-pack/plugins/ml/public/application/components/navigation_menu/date_picker_wrapper/date_picker_wrapper.test.tsx index 536cc26888a98..b794e6bbdf2bc 100644 --- a/x-pack/plugins/ml/public/application/components/navigation_menu/date_picker_wrapper/date_picker_wrapper.test.tsx +++ b/x-pack/plugins/ml/public/application/components/navigation_menu/date_picker_wrapper/date_picker_wrapper.test.tsx @@ -104,7 +104,7 @@ const MockedEuiSuperDatePicker = EuiSuperDatePicker as jest.MockedFunction< describe('Navigation Menu: ', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); MockedEuiSuperDatePicker.mockClear(); }); diff --git a/x-pack/plugins/ml/public/application/routing/use_resolver.test.ts b/x-pack/plugins/ml/public/application/routing/use_resolver.test.ts index 2ff7d4b024800..d174c4c2c7e3f 100644 --- a/x-pack/plugins/ml/public/application/routing/use_resolver.test.ts +++ b/x-pack/plugins/ml/public/application/routing/use_resolver.test.ts @@ -38,7 +38,7 @@ const redirectToJobsManagementPage = jest.fn(() => Promise.resolve()); describe('useResolver', () => { afterEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { jest.advanceTimersByTime(0); diff --git a/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.test.ts b/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.test.ts index a4874b9c13dd1..ad78677ad0f1f 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.test.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.test.ts @@ -37,7 +37,7 @@ describe('AnomalyExplorerChartsService', () => { }; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); mlApiServicesMock.jobs.jobForCloning.mockImplementation(() => Promise.resolve({})); diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/use_anomaly_charts_input_resolver.test.ts b/x-pack/plugins/ml/public/embeddables/anomaly_charts/use_anomaly_charts_input_resolver.test.ts index 4231f08b00c45..112863f560df3 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/use_anomaly_charts_input_resolver.test.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/use_anomaly_charts_input_resolver.test.ts @@ -48,7 +48,7 @@ describe('useAnomalyChartsInputResolver', () => { }; beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const jobIds = ['test-job']; embeddableInput = new BehaviorSubject({ diff --git a/x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js index f2e952c96e88f..7984b8c23cdc5 100644 --- a/x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js +++ b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js @@ -171,7 +171,7 @@ describe('SetupModeRenderer', () => { it('should use a new product found in the api response', () => { const newProduct = { id: 1 }; - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); jest.doMock('../../lib/setup_mode', () => ({ getSetupModeState: () => ({ supported: true, diff --git a/x-pack/plugins/observability/public/components/shared/date_picker/date_picker.test.tsx b/x-pack/plugins/observability/public/components/shared/date_picker/date_picker.test.tsx index 138018e104c8a..929425d2d150a 100644 --- a/x-pack/plugins/observability/public/components/shared/date_picker/date_picker.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/date_picker/date_picker.test.tsx @@ -133,7 +133,7 @@ describe('DatePicker', () => { }); it('enables auto-refresh when refreshPaused is false', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const { wrapper } = mountDatePicker({ rangeFrom: 'now-15m', rangeTo: 'now', @@ -148,7 +148,7 @@ describe('DatePicker', () => { }); it('disables auto-refresh when refreshPaused is true', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); mountDatePicker({ rangeFrom: 'now-15m', rangeTo: 'now', diff --git a/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts b/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts index 550a50ba112a8..1611d3ee601bd 100644 --- a/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts +++ b/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts @@ -20,6 +20,9 @@ export const getSLOMappingsTemplate = (name: string) => ({ type: 'keyword', ignore_above: 256, }, + revision: { + type: 'long', + }, numerator: { type: 'long', }, @@ -29,6 +32,25 @@ export const getSLOMappingsTemplate = (name: string) => ({ context: { type: 'flattened', }, + _internal: { + properties: { + name: { type: 'keyword', ignore_above: 256 }, + budgeting_method: { type: 'keyword' }, + objective: { + properties: { + target: { type: 'double' }, + timeslice_target: { type: 'double' }, + timeslice_window: { type: 'keyword' }, + }, + }, + time_window: { + properties: { + duration: { type: 'keyword' }, + is_rolling: { type: 'boolean' }, + }, + }, + }, + }, }, }, }, diff --git a/x-pack/plugins/observability/server/saved_objects/slo.ts b/x-pack/plugins/observability/server/saved_objects/slo.ts index a088765a988a3..461896a35f84e 100644 --- a/x-pack/plugins/observability/server/saved_objects/slo.ts +++ b/x-pack/plugins/observability/server/saved_objects/slo.ts @@ -42,8 +42,11 @@ export const slo: SavedObjectsType = { objective: { properties: { target: { type: 'float' }, + timeslice_target: { type: 'float' }, + timeslice_window: { type: 'keyword' }, }, }, + revision: { type: 'short' }, created_at: { type: 'date' }, updated_at: { type: 'date' }, }, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap index 61fadab240ae7..187126b8e8efd 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap @@ -57,6 +57,31 @@ Object { "field": "@timestamp", }, }, + "slo._internal.budgeting_method": Object { + "terms": Object { + "field": "slo._internal.budgeting_method", + }, + }, + "slo._internal.name": Object { + "terms": Object { + "field": "slo._internal.name", + }, + }, + "slo._internal.objective.target": Object { + "terms": Object { + "field": "slo._internal.objective.target", + }, + }, + "slo._internal.time_window.duration": Object { + "terms": Object { + "field": "slo._internal.time_window.duration", + }, + }, + "slo._internal.time_window.is_rolling": Object { + "terms": Object { + "field": "slo._internal.time_window.is_rolling", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", @@ -106,6 +131,36 @@ Object { }, }, "runtime_mappings": Object { + "slo._internal.budgeting_method": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo._internal.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo._internal.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, + "slo._internal.time_window.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo._internal.time_window.is_rolling": Object { + "script": Object { + "source": "emit(true)", + }, + "type": "boolean", + }, "slo.id": Object { "script": Object { "source": Any, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap index 51a0ee31581a2..3a7826cb9d8b5 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap @@ -62,6 +62,31 @@ Object { "field": "@timestamp", }, }, + "slo._internal.budgeting_method": Object { + "terms": Object { + "field": "slo._internal.budgeting_method", + }, + }, + "slo._internal.name": Object { + "terms": Object { + "field": "slo._internal.name", + }, + }, + "slo._internal.objective.target": Object { + "terms": Object { + "field": "slo._internal.objective.target", + }, + }, + "slo._internal.time_window.duration": Object { + "terms": Object { + "field": "slo._internal.time_window.duration", + }, + }, + "slo._internal.time_window.is_rolling": Object { + "terms": Object { + "field": "slo._internal.time_window.is_rolling", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", @@ -111,6 +136,36 @@ Object { }, }, "runtime_mappings": Object { + "slo._internal.budgeting_method": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo._internal.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo._internal.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, + "slo._internal.time_window.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo._internal.time_window.is_rolling": Object { + "script": Object { + "source": "emit(true)", + }, + "type": "boolean", + }, "slo.id": Object { "script": Object { "source": Any, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap index 4fac897473239..5fed8a8e08977 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -141,6 +141,31 @@ Object { "field": "@timestamp", }, }, + "slo._internal.budgeting_method": Object { + "terms": Object { + "field": "slo._internal.budgeting_method", + }, + }, + "slo._internal.name": Object { + "terms": Object { + "field": "slo._internal.name", + }, + }, + "slo._internal.objective.target": Object { + "terms": Object { + "field": "slo._internal.objective.target", + }, + }, + "slo._internal.time_window.duration": Object { + "terms": Object { + "field": "slo._internal.time_window.duration", + }, + }, + "slo._internal.time_window.is_rolling": Object { + "terms": Object { + "field": "slo._internal.time_window.is_rolling", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", @@ -171,6 +196,36 @@ Object { }, }, "runtime_mappings": Object { + "slo._internal.budgeting_method": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo._internal.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo._internal.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, + "slo._internal.time_window.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo._internal.time_window.is_rolling": Object { + "script": Object { + "source": "emit(true)", + }, + "type": "boolean", + }, "slo.id": Object { "script": Object { "source": Any, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts index 68848c7f1aa3f..35a9b5088ca70 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - AggregationsCalendarInterval, - MappingRuntimeFieldType, - TransformPutTransformRequest, -} from '@elastic/elasticsearch/lib/api/types'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; import { InvalidTransformError } from '../../../errors'; import { ALL_VALUE, apmTransactionDurationIndicatorSchema } from '../../../types/schema'; import { @@ -23,7 +19,7 @@ import { TransformGenerator } from '.'; const APM_SOURCE_INDEX = 'metrics-apm*'; -export class ApmTransactionDurationTransformGenerator implements TransformGenerator { +export class ApmTransactionDurationTransformGenerator extends TransformGenerator { public getTransformParams(slo: SLO): TransformPutTransformRequest { if (!apmTransactionDurationIndicatorSchema.is(slo.indicator)) { throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); @@ -33,7 +29,7 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera this.buildTransformId(slo), this.buildSource(slo, slo.indicator), this.buildDestination(), - this.buildGroupBy(), + this.buildCommonGroupBy(slo), this.buildAggregations(slo.indicator) ); } @@ -78,20 +74,7 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera return { index: APM_SOURCE_INDEX, - runtime_mappings: { - 'slo.id': { - type: 'keyword' as MappingRuntimeFieldType, - script: { - source: `emit('${slo.id}')`, - }, - }, - 'slo.revision': { - type: 'long' as MappingRuntimeFieldType, - script: { - source: `emit(${slo.revision})`, - }, - }, - }, + runtime_mappings: this.buildCommonRuntimeMappings(slo), query: { bool: { filter: [ @@ -114,27 +97,6 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera }; } - private buildGroupBy() { - return { - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, - '@timestamp': { - date_histogram: { - field: '@timestamp', - calendar_interval: '1m' as AggregationsCalendarInterval, - }, - }, - }; - } - private buildAggregations(indicator: APMTransactionDurationIndicator) { const truncatedThreshold = Math.trunc(indicator.params['threshold.us']); diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts index 41ab541cdb4b6..0da9f93e8d145 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - AggregationsCalendarInterval, - MappingRuntimeFieldType, - TransformPutTransformRequest, -} from '@elastic/elasticsearch/lib/api/types'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; import { InvalidTransformError } from '../../../errors'; import { ALL_VALUE, apmTransactionErrorRateIndicatorSchema } from '../../../types/schema'; import { getSLOTransformTemplate } from '../../../assets/transform_templates/slo_transform_template'; @@ -25,7 +21,7 @@ const APM_SOURCE_INDEX = 'metrics-apm*'; const ALLOWED_STATUS_CODES = ['2xx', '3xx', '4xx', '5xx']; const DEFAULT_GOOD_STATUS_CODES = ['2xx', '3xx', '4xx']; -export class ApmTransactionErrorRateTransformGenerator implements TransformGenerator { +export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator { public getTransformParams(slo: SLO): TransformPutTransformRequest { if (!apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) { throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); @@ -35,7 +31,7 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener this.buildTransformId(slo), this.buildSource(slo, slo.indicator), this.buildDestination(), - this.buildGroupBy(), + this.buildCommonGroupBy(slo), this.buildAggregations(slo, slo.indicator) ); } @@ -80,20 +76,7 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener return { index: APM_SOURCE_INDEX, - runtime_mappings: { - 'slo.id': { - type: 'keyword' as MappingRuntimeFieldType, - script: { - source: `emit('${slo.id}')`, - }, - }, - 'slo.revision': { - type: 'long' as MappingRuntimeFieldType, - script: { - source: `emit(${slo.revision})`, - }, - }, - }, + runtime_mappings: this.buildCommonRuntimeMappings(slo), query: { bool: { filter: [ @@ -116,27 +99,6 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener }; } - private buildGroupBy() { - return { - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, - '@timestamp': { - date_histogram: { - field: '@timestamp', - calendar_interval: '1m' as AggregationsCalendarInterval, - }, - }, - }; - } - private buildAggregations(slo: SLO, indicator: APMTransactionErrorRateIndicator) { const goodStatusCodesFilter = this.getGoodStatusCodesFilter(indicator.params.good_status_codes); diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts index b444a196960d3..c2228b6a3095c 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - AggregationsCalendarInterval, - MappingRuntimeFieldType, - TransformPutTransformRequest, -} from '@elastic/elasticsearch/lib/api/types'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { InvalidTransformError } from '../../../errors'; @@ -23,7 +19,7 @@ import { } from '../../../assets/constants'; import { KQLCustomIndicator, SLO } from '../../../types/models'; -export class KQLCustomTransformGenerator implements TransformGenerator { +export class KQLCustomTransformGenerator extends TransformGenerator { public getTransformParams(slo: SLO): TransformPutTransformRequest { if (!kqlCustomIndicatorSchema.is(slo.indicator)) { throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); @@ -33,7 +29,7 @@ export class KQLCustomTransformGenerator implements TransformGenerator { this.buildTransformId(slo), this.buildSource(slo, slo.indicator), this.buildDestination(), - this.buildGroupBy(), + this.buildCommonGroupBy(slo), this.buildAggregations(slo, slo.indicator) ); } @@ -46,20 +42,7 @@ export class KQLCustomTransformGenerator implements TransformGenerator { const filter = getElastichsearchQueryOrThrow(indicator.params.query_filter); return { index: indicator.params.index, - runtime_mappings: { - 'slo.id': { - type: 'keyword' as MappingRuntimeFieldType, - script: { - source: `emit('${slo.id}')`, - }, - }, - 'slo.revision': { - type: 'long' as MappingRuntimeFieldType, - script: { - source: `emit(${slo.revision})`, - }, - }, - }, + runtime_mappings: this.buildCommonRuntimeMappings(slo), query: filter, }; } @@ -71,27 +54,6 @@ export class KQLCustomTransformGenerator implements TransformGenerator { }; } - private buildGroupBy() { - return { - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, - '@timestamp': { - date_histogram: { - field: '@timestamp', - calendar_interval: '1m' as AggregationsCalendarInterval, - }, - }, - }; - } - private buildAggregations(slo: SLO, indicator: KQLCustomIndicator) { const numerator = getElastichsearchQueryOrThrow(indicator.params.numerator); const denominator = getElastichsearchQueryOrThrow(indicator.params.denominator); diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts index 3965e809373c8..cd0ceaa602c22 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts @@ -5,9 +5,147 @@ * 2.0. */ -import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { MappingRuntimeFieldType } from '@elastic/elasticsearch/lib/api/types'; +import { + AggregationsCalendarInterval, + TransformPutTransformRequest, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + calendarAlignedTimeWindowSchema, + rollingTimeWindowSchema, + timeslicesBudgetingMethodSchema, +} from '../../../types/schema'; import { SLO } from '../../../types/models'; -export interface TransformGenerator { - getTransformParams(slo: SLO): TransformPutTransformRequest; +export abstract class TransformGenerator { + public abstract getTransformParams(slo: SLO): TransformPutTransformRequest; + + public buildCommonRuntimeMappings(slo: SLO) { + return { + 'slo.id': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.id}')`, + }, + }, + 'slo.revision': { + type: 'long' as MappingRuntimeFieldType, + script: { + source: `emit(${slo.revision})`, + }, + }, + 'slo._internal.name': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.name}')`, + }, + }, + 'slo._internal.budgeting_method': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.budgeting_method}')`, + }, + }, + 'slo._internal.objective.target': { + type: 'double' as MappingRuntimeFieldType, + script: { + source: `emit(${slo.objective.target})`, + }, + }, + ...(timeslicesBudgetingMethodSchema.is(slo.budgeting_method) && { + 'slo._internal.objective.timeslice_target': { + type: 'double' as MappingRuntimeFieldType, + script: { + source: `emit(${slo.objective.timeslice_target})`, + }, + }, + 'slo._internal.objective.timeslice_window': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.objective.timeslice_window?.format()}')`, + }, + }, + }), + 'slo._internal.time_window.duration': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.time_window.duration.format()}')`, + }, + }, + ...(calendarAlignedTimeWindowSchema.is(slo.time_window) && { + 'slo._internal.time_window.is_rolling': { + type: 'boolean' as MappingRuntimeFieldType, + script: { + source: `emit(false)`, + }, + }, + }), + ...(rollingTimeWindowSchema.is(slo.time_window) && { + 'slo._internal.time_window.is_rolling': { + type: 'boolean' as MappingRuntimeFieldType, + script: { + source: `emit(true)`, + }, + }, + }), + }; + } + + public buildCommonGroupBy(slo: SLO) { + return { + 'slo.id': { + terms: { + field: 'slo.id', + }, + }, + 'slo.revision': { + terms: { + field: 'slo.revision', + }, + }, + 'slo._internal.name': { + terms: { + field: 'slo._internal.name', + }, + }, + 'slo._internal.budgeting_method': { + terms: { + field: 'slo._internal.budgeting_method', + }, + }, + 'slo._internal.objective.target': { + terms: { + field: 'slo._internal.objective.target', + }, + }, + 'slo._internal.time_window.duration': { + terms: { + field: 'slo._internal.time_window.duration', + }, + }, + 'slo._internal.time_window.is_rolling': { + terms: { + field: 'slo._internal.time_window.is_rolling', + }, + }, + ...(timeslicesBudgetingMethodSchema.is(slo.budgeting_method) && { + 'slo._internal.objective.timeslice_target': { + terms: { + field: 'slo._internal.objective.timeslice_target', + }, + }, + 'slo._internal.objective.timeslice_window': { + terms: { + field: 'slo._internal.objective.timeslice_window', + }, + }, + }), + '@timestamp': { + date_histogram: { + field: '@timestamp', + calendar_interval: '1m' as AggregationsCalendarInterval, + }, + }, + }; + } } diff --git a/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts b/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts index 1951888d734fd..696e04f5c13bc 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts @@ -138,13 +138,13 @@ describe('TransformManager', () => { }); }); -class DummyTransformGenerator implements TransformGenerator { +class DummyTransformGenerator extends TransformGenerator { getTransformParams(slo: SLO): TransformPutTransformRequest { return {} as TransformPutTransformRequest; } } -class FailTransformGenerator implements TransformGenerator { +class FailTransformGenerator extends TransformGenerator { getTransformParams(slo: SLO): TransformPutTransformRequest { throw new Error('Some error'); } diff --git a/x-pack/plugins/observability/server/types/models/duration.test.ts b/x-pack/plugins/observability/server/types/models/duration.test.ts index 4383c8e3ddd79..6f6b2dcb0c2d3 100644 --- a/x-pack/plugins/observability/server/types/models/duration.test.ts +++ b/x-pack/plugins/observability/server/types/models/duration.test.ts @@ -20,6 +20,18 @@ describe('Duration', () => { expect(() => new Duration(1, 'z' as DurationUnit)).toThrow('invalid duration unit'); }); + describe('format', () => { + it('formats the duration correctly', () => { + expect(new Duration(1, DurationUnit.m).format()).toBe('1m'); + expect(new Duration(1, DurationUnit.h).format()).toBe('1h'); + expect(new Duration(1, DurationUnit.d).format()).toBe('1d'); + expect(new Duration(1, DurationUnit.w).format()).toBe('1w'); + expect(new Duration(1, DurationUnit.M).format()).toBe('1M'); + expect(new Duration(1, DurationUnit.Q).format()).toBe('1Q'); + expect(new Duration(1, DurationUnit.Y).format()).toBe('1Y'); + }); + }); + describe('isShorterThan', () => { it('returns true when the current duration is shorter than the other duration', () => { const short = new Duration(1, DurationUnit.m); diff --git a/x-pack/plugins/observability/server/types/models/duration.ts b/x-pack/plugins/observability/server/types/models/duration.ts index e34a748e30ba6..aafed067f0bae 100644 --- a/x-pack/plugins/observability/server/types/models/duration.ts +++ b/x-pack/plugins/observability/server/types/models/duration.ts @@ -33,6 +33,10 @@ class Duration { const currentDurationMoment = moment.duration(this.value, toMomentUnitOfTime(this.unit)); return currentDurationMoment.asSeconds() < otherDurationMoment.asSeconds(); } + + format(): string { + return `${this.value}${this.unit}`; + } } const toMomentUnitOfTime = (unit: DurationUnit): moment.unitOfTime.Diff => { diff --git a/x-pack/plugins/observability/server/types/schema/duration.ts b/x-pack/plugins/observability/server/types/schema/duration.ts index b4fa5065063f3..c7a3815140a6a 100644 --- a/x-pack/plugins/observability/server/types/schema/duration.ts +++ b/x-pack/plugins/observability/server/types/schema/duration.ts @@ -24,7 +24,7 @@ const durationType = new t.Type( return t.failure(input, context); } }), - (duration: Duration): string => `${duration.value}${duration.unit}` + (duration: Duration): string => duration.format() ); export { durationType }; diff --git a/x-pack/plugins/observability/server/ui_settings.ts b/x-pack/plugins/observability/server/ui_settings.ts index a5b111569e311..f272db404b7b8 100644 --- a/x-pack/plugins/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability/server/ui_settings.ts @@ -197,13 +197,13 @@ export const uiSettings: Record = { [apmServiceInventoryOptimizedSorting]: { category: [observabilityFeatureId], name: i18n.translate('xpack.observability.apmServiceInventoryOptimizedSorting', { - defaultMessage: 'Optimize APM Service Inventory page load performance', + defaultMessage: 'Optimize services list load performance in APM', }), description: i18n.translate( 'xpack.observability.apmServiceInventoryOptimizedSortingDescription', { defaultMessage: - '{technicalPreviewLabel} Default APM Service Inventory page sort (for Services without Machine Learning applied) to sort by Service Name. {feedbackLink}.', + '{technicalPreviewLabel} Default APM Service Inventory and Storage Explorer pages sort (for Services without Machine Learning applied) to sort by Service Name. {feedbackLink}.', values: { technicalPreviewLabel: `[${technicalPreviewLabel}]`, feedbackLink: feedbackLink({ href: 'https://ela.st/feedback-apm-page-performance' }), diff --git a/x-pack/plugins/profiling/public/utils/formatters/as_number.ts b/x-pack/plugins/profiling/public/utils/formatters/as_number.ts index f7b67bafbf7f7..365cd876ad69e 100644 --- a/x-pack/plugins/profiling/public/utils/formatters/as_number.ts +++ b/x-pack/plugins/profiling/public/utils/formatters/as_number.ts @@ -11,18 +11,18 @@ export function asNumber(value: number): string { } value = Math.round(value * 100) / 100; - if (value < 0.01) { + if (Math.abs(value) < 0.01) { return '~0.00'; } - if (value < 1e3) { + if (Math.abs(value) < 1e3) { return value.toString(); } - if (value < 1e6) { + if (Math.abs(value) < 1e6) { return `${asNumber(value / 1e3)}k`; } - if (value < 1e9) { + if (Math.abs(value) < 1e9) { return `${asNumber(value / 1e6)}m`; } diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/list/remote_clusters_list.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/list/remote_clusters_list.test.js index 63367cfd6d001..4f404ee653496 100644 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/list/remote_clusters_list.test.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/list/remote_clusters_list.test.js @@ -34,7 +34,7 @@ describe('', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js index 7a4eae8d0841f..a087cabe64d96 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js @@ -26,7 +26,7 @@ describe('Cloning a rollup job through create job wizard', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js index 565badc85403e..be3c1f09b6257 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js @@ -23,7 +23,7 @@ describe('Create Rollup Job, step 2: Date histogram', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js index 1166462a833de..af35dc9063c1a 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js @@ -23,7 +23,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js index 540b9b7bb0dbc..c22da0d2fa476 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js @@ -23,7 +23,7 @@ describe('Create Rollup Job, step 1: Logistics', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js index 9f8b108049e23..6e4ffea0367a9 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js @@ -23,7 +23,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js index 4927233b958b9..36d33d6ab1874 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js @@ -35,7 +35,7 @@ describe('Create Rollup Job, step 6: Review', () => { let component; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); }); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js index e4998d7e41ca7..6535b88311dbc 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js @@ -22,7 +22,7 @@ describe('Create Rollup Job, step 3: Terms', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js index ccb177c17a14b..5cd82054ce0e4 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js @@ -38,7 +38,7 @@ describe('', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js index 03833cb3a02e8..20728477de7fc 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js @@ -31,7 +31,7 @@ describe('Smoke test cloning an existing rollup job from job list', () => { let startMock; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); startMock = coreMock.createStart(); setHttp(startMock.http); }); diff --git a/x-pack/plugins/runtime_fields/public/components/runtime_field_editor/runtime_field_editor.test.tsx b/x-pack/plugins/runtime_fields/public/components/runtime_field_editor/runtime_field_editor.test.tsx index 4a7f8d07db7e1..7dece57a4ea10 100644 --- a/x-pack/plugins/runtime_fields/public/components/runtime_field_editor/runtime_field_editor.test.tsx +++ b/x-pack/plugins/runtime_fields/public/components/runtime_field_editor/runtime_field_editor.test.tsx @@ -37,7 +37,7 @@ describe('Runtime field editor', () => { const lastOnChangeCall = (): FormState[] => onChange.mock.calls[onChange.mock.calls.length - 1]; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/security/public/analytics/analytics_service.test.ts b/x-pack/plugins/security/public/analytics/analytics_service.test.ts index be13fa25c1c8d..19643e68b4203 100644 --- a/x-pack/plugins/security/public/analytics/analytics_service.test.ts +++ b/x-pack/plugins/security/public/analytics/analytics_service.test.ts @@ -57,7 +57,7 @@ describe('AnalyticsService', () => { }); it('throttle reporting of the authentication type events', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const mockCore = coreMock.createStart(); mockCore.http.post.mockResolvedValue({ signature: 'some-signature', timestamp: 1234 }); diff --git a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts index 282bf7beb68be..f33b8659fb27f 100644 --- a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts +++ b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts @@ -226,4 +226,31 @@ export const kibanaFeatures = [ }, ], }), + createFeature({ + id: 'with_require_all_spaces_sub_features', + name: 'Require all spaces Sub Features', + subFeatures: [ + { + name: 'Require all spaces Sub Feature', + requireAllSpaces: true, + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + id: 'cool_toggle_1', + name: 'Cool toggle 1', + includeIn: 'read', + savedObject: { + all: [], + read: [], + }, + ui: ['cool_toggle_1-ui'], + }, + ], + }, + ], + }, + ], + }), ]; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx index af5ef0a0ccb00..7c81bb4a00de8 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx @@ -259,7 +259,7 @@ describe('field level security', () => { }); test('does not query for available fields when a request is already in flight', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const testProps = { ...props, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index f3b63bf32b5ff..7f5ac97e41edf 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -107,6 +107,10 @@ describe('FeatureTable', () => { primaryFeaturePrivilege: 'none', subFeaturePrivileges: [], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -157,6 +161,14 @@ describe('FeatureTable', () => { } : { subFeaturePrivileges: [] }), }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'all', + ...(canCustomizeSubFeaturePrivileges + ? { + subFeaturePrivileges: ['cool_toggle_1'], + } + : { subFeaturePrivileges: [] }), + }, }); }); @@ -208,6 +220,10 @@ describe('FeatureTable', () => { } : { subFeaturePrivileges: [] }), }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -302,6 +318,10 @@ describe('FeatureTable', () => { primaryFeaturePrivilege: 'read', subFeaturePrivileges: ['cool_all'], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -684,6 +704,10 @@ describe('FeatureTable', () => { 'cool_all', ], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -722,6 +746,10 @@ describe('FeatureTable', () => { primaryFeaturePrivilege: 'all', subFeaturePrivileges: [], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -760,6 +788,10 @@ describe('FeatureTable', () => { primaryFeaturePrivilege: 'read', subFeaturePrivileges: [], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); @@ -888,6 +920,10 @@ describe('FeatureTable', () => { primaryFeaturePrivilege: 'none', subFeaturePrivileges: [], }, + with_require_all_spaces_sub_features: { + primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], + }, }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index 505dd8e70024e..33f9f2879b4f7 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -250,6 +250,7 @@ export class FeatureTable extends Component { selectedFeaturePrivileges={ this.props.role.kibana[this.props.privilegeIndex].feature[feature.id] ?? [] } + allSpacesSelected={this.props.allSpacesSelected} disabled={this.props.disabled} licenseAllowsSubFeatPrivCustomization={ this.props.canCustomizeSubFeaturePrivileges diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx index 8e435dc43ef20..c7ab5a2be7890 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx @@ -49,6 +49,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['minimal_read']} onChange={jest.fn()} licenseAllowsSubFeatPrivCustomization={false} + allSpacesSelected={false} /> ); @@ -86,6 +87,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['none']} onChange={jest.fn()} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -118,6 +120,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['minimal_read']} onChange={jest.fn()} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -153,6 +156,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['read']} onChange={jest.fn()} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -186,6 +190,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['read']} onChange={jest.fn()} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -223,6 +228,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['read']} onChange={onChange} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -263,6 +269,7 @@ describe('FeatureTableExpandedRow', () => { selectedFeaturePrivileges={['minimal_read', 'cool_read', 'cool_toggle_2']} onChange={onChange} licenseAllowsSubFeatPrivCustomization={true} + allSpacesSelected={false} /> ); @@ -272,4 +279,76 @@ describe('FeatureTableExpandedRow', () => { expect(onChange).toHaveBeenCalledWith('with_sub_features', ['read']); }); + + it('require all spaces enabled and allSpacesSelected is false: option is disabled', () => { + const role = createRole([ + { + base: [], + feature: { + with_require_all_spaces_sub_features: ['cool_toggle_1'], + }, + spaces: ['foo'], + }, + ]); + + const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); + const calculator = new PrivilegeFormCalculator(kibanaPrivileges, role); + const feature = kibanaPrivileges.getSecuredFeature('with_require_all_spaces_sub_features'); + const onChange = jest.fn(); + + const wrapper = mountWithIntl( + + ); + + act(() => { + findTestSubject(wrapper, 'customizeSubFeaturePrivileges').simulate('click'); + }); + + const object = wrapper.find('SubFeatureForm'); + expect(object.props()).toMatchObject({ disabled: true }); + }); + + it('require all spaces enabled and allSpacesSelected is true: option is enabled', () => { + const role = createRole([ + { + base: [], + feature: { + with_require_all_spaces_sub_features: ['cool_toggle_1'], + }, + spaces: ['foo'], + }, + ]); + + const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); + const calculator = new PrivilegeFormCalculator(kibanaPrivileges, role); + const feature = kibanaPrivileges.getSecuredFeature('with_require_all_spaces_sub_features'); + const onChange = jest.fn(); + + const wrapper = mountWithIntl( + + ); + + act(() => { + findTestSubject(wrapper, 'customizeSubFeaturePrivileges').simulate('click'); + }); + + const object = wrapper.find('SubFeatureForm'); + expect(object.props()).toMatchObject({ disabled: false }); + }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx index a0726ad2ef566..e5e28c4547374 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx @@ -21,6 +21,7 @@ interface Props { privilegeCalculator: PrivilegeFormCalculator; privilegeIndex: number; selectedFeaturePrivileges: string[]; + allSpacesSelected: boolean; disabled?: boolean; licenseAllowsSubFeatPrivCustomization: boolean; onChange: (featureId: string, featurePrivileges: string[]) => void; @@ -32,6 +33,7 @@ export const FeatureTableExpandedRow = ({ privilegeIndex, privilegeCalculator, selectedFeaturePrivileges, + allSpacesSelected, disabled, licenseAllowsSubFeatPrivCustomization, }: Props) => { @@ -110,6 +112,8 @@ export const FeatureTableExpandedRow = ({

{feature.getSubFeatures().map((subFeature) => { + const isDisabledDueToSpaceSelection = subFeature.requireAllSpaces && !allSpacesSelected; + return ( onChange(feature.id, updatedPrivileges)} selectedFeaturePrivileges={selectedFeaturePrivileges} - disabled={disabled || !isCustomizing} + disabled={disabled || !isCustomizing || isDisabledDueToSpaceSelection} /> ); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx index d123773fed1c7..8af3bcdb2fef3 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx @@ -5,7 +5,14 @@ * 2.0. */ -import { EuiButtonGroup, EuiCheckbox, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { + EuiButtonGroup, + EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, + EuiIconTip, + EuiText, +} from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; @@ -33,6 +40,27 @@ export const SubFeatureForm = (props: Props) => { .getPrivilegeGroups() .filter((group) => group.privileges.length > 0); + const getTooltip = () => { + if (!props.subFeature.privilegesTooltip) { + return null; + } + const tooltipContent = ( + +

{props.subFeature.privilegesTooltip}

+
+ ); + return ( + + ); + }; + if (groupsWithPrivileges.length === 0) { return null; } @@ -40,7 +68,9 @@ export const SubFeatureForm = (props: Props) => { return ( - {props.subFeature.name} + + {props.subFeature.name} {getTooltip()} + {groupsWithPrivileges.map(renderPrivilegeGroup)} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts index a6714cb7a2d83..61be3af6eb1c8 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts @@ -53,6 +53,11 @@ describe('PrivilegeSummaryCalculator', () => { primary: undefined, subFeature: [], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: undefined, + subFeature: [], + }, }); }); @@ -99,6 +104,13 @@ describe('PrivilegeSummaryCalculator', () => { }), subFeature: ['cool_all', 'cool_read', 'cool_toggle_1', 'cool_toggle_2'], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: expect.objectContaining({ + id: 'all', + }), + subFeature: ['cool_toggle_1'], + }, }); }); @@ -155,6 +167,13 @@ describe('PrivilegeSummaryCalculator', () => { 'cool_excluded_toggle', ], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: expect.objectContaining({ + id: 'all', + }), + subFeature: ['cool_toggle_1'], + }, }); }); @@ -214,6 +233,13 @@ describe('PrivilegeSummaryCalculator', () => { 'cool_excluded_toggle', ], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: expect.objectContaining({ + id: 'all', + }), + subFeature: ['cool_toggle_1'], + }, }); }); @@ -255,6 +281,13 @@ describe('PrivilegeSummaryCalculator', () => { }), subFeature: ['cool_all', 'cool_read', 'cool_toggle_1', 'cool_toggle_2'], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: expect.objectContaining({ + id: 'all', + }), + subFeature: ['cool_toggle_1'], + }, }); }); @@ -294,6 +327,11 @@ describe('PrivilegeSummaryCalculator', () => { primary: undefined, subFeature: [], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: undefined, + subFeature: [], + }, }); }); @@ -333,6 +371,11 @@ describe('PrivilegeSummaryCalculator', () => { primary: undefined, subFeature: [], }, + with_require_all_spaces_sub_features: { + hasCustomizedSubFeaturePrivileges: false, + primary: undefined, + subFeature: [], + }, }); }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx index d54866c88f7ef..62ad9bc83b1cc 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx @@ -90,6 +90,15 @@ const expectNoPrivileges = (displayedPrivileges: any, expectSubFeatures: boolean }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'None', + ...maybeExpectSubFeaturePrivileges(expectSubFeatures, { + 'Require all spaces Sub Feature': [], + }), + }, + }, }); }; @@ -248,6 +257,15 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'All', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -310,6 +328,15 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'All', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -370,6 +397,15 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'All', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -432,6 +468,15 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'None', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': [], + }), + }, + }, }); }); @@ -522,6 +567,22 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'All', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -614,6 +675,22 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -706,6 +783,22 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'None', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': [], + }), + }, + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); @@ -800,6 +893,22 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'None', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': [], + }), + }, + 'default, space-1': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'None', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': [], + }), + }, + }, }); }); @@ -925,6 +1034,29 @@ describe('PrivilegeSummaryTable', () => { }), }, }, + with_require_all_spaces_sub_features: { + '*': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + default: { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'All', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + 'space-1, space-2': { + hasCustomizedSubFeaturePrivileges: false, + primaryFeaturePrivilege: 'Read', + ...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, { + 'Require all spaces Sub Feature': ['Cool toggle 1'], + }), + }, + }, }); }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx index 8f10acb2403aa..71876eeed963d 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx @@ -79,6 +79,10 @@ describe('PrivilegeSpaceForm', () => { "primaryFeaturePrivilege": "none", "subFeaturePrivileges": Array [], }, + "with_require_all_spaces_sub_features": Object { + "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], + }, "with_sub_features": Object { "primaryFeaturePrivilege": "none", "subFeaturePrivileges": Array [], @@ -129,6 +133,12 @@ describe('PrivilegeSpaceForm', () => { "primaryFeaturePrivilege": "all", "subFeaturePrivileges": Array [], }, + "with_require_all_spaces_sub_features": Object { + "primaryFeaturePrivilege": "all", + "subFeaturePrivileges": Array [ + "cool_toggle_1", + ], + }, "with_sub_features": Object { "primaryFeaturePrivilege": "all", "subFeaturePrivileges": Array [ @@ -185,6 +195,10 @@ describe('PrivilegeSpaceForm', () => { "primaryFeaturePrivilege": "none", "subFeaturePrivileges": Array [], }, + "with_require_all_spaces_sub_features": Object { + "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], + }, "with_sub_features": Object { "primaryFeaturePrivilege": "read", "subFeaturePrivileges": Array [ @@ -286,6 +300,10 @@ describe('PrivilegeSpaceForm', () => { "primaryFeaturePrivilege": "none", "subFeaturePrivileges": Array [], }, + "with_require_all_spaces_sub_features": Object { + "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], + }, "with_sub_features": Object { "primaryFeaturePrivilege": "read", "subFeaturePrivileges": Array [ @@ -346,6 +364,7 @@ describe('PrivilegeSpaceForm', () => { with_excluded_sub_features: ['read'], no_sub_features: ['read'], with_sub_features: ['read'], + with_require_all_spaces_sub_features: ['read'], }, spaces: ['foo'], }, @@ -451,6 +470,7 @@ describe('PrivilegeSpaceForm', () => { with_excluded_sub_features: ['read'], no_sub_features: ['read'], with_sub_features: ['read'], + with_require_all_spaces_sub_features: ['read'], }, spaces: ['foo'], }, @@ -493,6 +513,7 @@ describe('PrivilegeSpaceForm', () => { no_sub_features: ['all'], no_sub_features_disabled_read: ['all'], with_sub_features: ['all'], + with_require_all_spaces_sub_features: ['all'], }, spaces: ['foo'], }, @@ -569,6 +590,7 @@ describe('PrivilegeSpaceForm', () => { no_sub_features: ['read'], no_sub_features_require_all_space: ['read'], with_sub_features: ['read'], + with_require_all_spaces_sub_features: ['read'], }, spaces: ['foo'], }, @@ -613,6 +635,7 @@ describe('PrivilegeSpaceForm', () => { with_excluded_sub_features: ['all'], no_sub_features: ['all'], with_sub_features: ['all'], + with_require_all_spaces_sub_features: ['all'], }, spaces: ['foo'], }, @@ -671,6 +694,7 @@ describe('PrivilegeSpaceForm', () => { no_sub_features: ['all'], no_sub_features_require_all_space: ['all'], with_sub_features: ['all'], + with_require_all_spaces_sub_features: ['all'], }, spaces: ['*'], }, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx index a26b9587d450a..d0120d64fa5ed 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx @@ -24,6 +24,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { remove } from 'lodash'; import React, { Component, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; @@ -472,9 +473,22 @@ export class PrivilegeSpaceForm extends Component { const primaryFeaturePrivilege = securedFeature ?.getPrimaryFeaturePrivileges({ includeMinimalFeaturePrivileges: true }) .find((pfp) => privileges.includes(pfp.id)) ?? { disabled: false, requireAllSpaces: false }; + + const areAllSpacesSelected = selectedSpaceIds.includes(ALL_SPACES_ID); + if (securedFeature) { + securedFeature.getSubFeatures().forEach((subFeature) => { + subFeature.privileges.forEach((currentPrivilege) => { + if (privileges.includes(currentPrivilege.id)) { + if (subFeature.requireAllSpaces && !areAllSpacesSelected) { + remove(privileges, (privilege) => privilege === currentPrivilege.id); + } + } + }); + }); + } const newFeaturePrivileges = primaryFeaturePrivilege?.disabled || - (primaryFeaturePrivilege?.requireAllSpaces && !selectedSpaceIds.includes(ALL_SPACES_ID)) + (primaryFeaturePrivilege?.requireAllSpaces && !areAllSpacesSelected) ? [] // The primary feature privilege cannot be selected; remove that and any selected sub-feature privileges, too : privileges; return { @@ -536,7 +550,12 @@ export class PrivilegeSpaceForm extends Component { newPrivileges = [nextFeaturePrivilege.id]; feature.getSubFeaturePrivileges().forEach((psf) => { if (Array.isArray(privileges) && privileges.includes(psf.id)) { - newPrivileges.push(psf.id); + if ( + !psf.requireAllSpaces || + (psf.requireAllSpaces && this.state.selectedSpaceIds.includes(ALL_SPACES_ID)) + ) { + newPrivileges.push(psf.id); + } } }); } diff --git a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts index 1f76b17a39e59..8c312ee7ea772 100644 --- a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts +++ b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts @@ -13,6 +13,7 @@ import { SubFeaturePrivilegeGroup } from './sub_feature_privilege_group'; export class SecuredSubFeature extends SubFeature { public readonly privileges: SubFeaturePrivilege[]; + public readonly privilegesTooltip: string; constructor( config: SubFeatureConfig, @@ -20,6 +21,8 @@ export class SecuredSubFeature extends SubFeature { ) { super(config); + this.privilegesTooltip = config.privilegesTooltip || ''; + this.privileges = []; for (const privilege of this.privilegeIterator()) { this.privileges.push(privilege); diff --git a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts index 45a51a45533c1..b5897654a6a38 100644 --- a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts +++ b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts @@ -20,4 +20,8 @@ export class SubFeaturePrivilege extends KibanaPrivilege { public get name() { return this.subPrivilegeConfig.name; } + + public get requireAllSpaces() { + return this.subPrivilegeConfig.requireAllSpaces ?? false; + } } diff --git a/x-pack/plugins/security/public/session/session_timeout.test.ts b/x-pack/plugins/security/public/session/session_timeout.test.ts index e43c1af6ac9c7..41e8907390296 100644 --- a/x-pack/plugins/security/public/session/session_timeout.test.ts +++ b/x-pack/plugins/security/public/session/session_timeout.test.ts @@ -25,7 +25,7 @@ import type { SessionInfo } from '../../common/types'; import { createSessionExpiredMock } from './session_expired.mock'; import { SessionTimeout, startTimer } from './session_timeout'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); jest.spyOn(window, 'addEventListener'); jest.spyOn(window, 'removeEventListener'); diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index dfd42c2260c5e..2cef6908355d0 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -25,7 +25,7 @@ import { RECORD_USAGE_INTERVAL, } from './audit_service'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); const logger = loggingSystemMock.createLogger(); const license = licenseMock.create(); diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index cd18a28e0d373..ceb0dab8a7f70 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -233,6 +233,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/snooze", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkEdit", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkDelete", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unsnooze", ] `); @@ -332,6 +333,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/snooze", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkEdit", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkDelete", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unsnooze", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", @@ -391,6 +393,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/snooze", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkEdit", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkDelete", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unsnooze", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/get", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getRuleState", @@ -499,6 +502,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/snooze", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkEdit", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/bulkDelete", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unsnooze", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/get", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getRuleState", diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index a11a4fa77bcdd..19dcd2d3a38cb 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -42,6 +42,7 @@ const writeOperations: Record = { 'unmuteAlert', 'snooze', 'bulkEdit', + 'bulkDelete', 'unsnooze', ], alert: ['update'], diff --git a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts index 219158bdda472..224ffeab0a0f4 100644 --- a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts +++ b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts @@ -88,7 +88,7 @@ describe('ElasticsearchService', () => { }); it('`watchOnlineStatus$` allows to schedule retry', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // Both ES and license are available. mockLicense.isEnabled.mockReturnValue(true); @@ -146,7 +146,7 @@ describe('ElasticsearchService', () => { }); it('`watchOnlineStatus$` cancels scheduled retry if status changes before retry timeout fires', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // Both ES and license are available. mockLicense.isEnabled.mockReturnValue(true); diff --git a/x-pack/plugins/security/server/lib/role_utils.ts b/x-pack/plugins/security/server/lib/role_utils.ts index c852079081821..3ec3247bf61a7 100644 --- a/x-pack/plugins/security/server/lib/role_utils.ts +++ b/x-pack/plugins/security/server/lib/role_utils.ts @@ -101,6 +101,22 @@ export const validateKibanaPrivileges = ( } } + kibanaFeature.subFeatures.forEach((subFeature) => { + if ( + subFeature.requireAllSpaces && + !forAllSpaces && + subFeature.privilegeGroups.some((group) => + group.privileges.some((privilege) => feature.includes(privilege.id)) + ) + ) { + errors.push( + `Sub-feature privilege [${kibanaFeature.name} - ${ + subFeature.name + }] requires all spaces to be selected but received [${priv.spaces.join(',')}]` + ); + } + }); + return errors; }); }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts index 842a3b74853b7..ed1648c069d4a 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.test.ts @@ -466,4 +466,86 @@ describe('validateKibanaPrivileges', () => { `Feature [foo] does not support privilege [read].`, ]); }); + + const fooSubFeature = new KibanaFeature({ + id: 'foo', + name: 'Foo', + privileges: { + all: { + savedObject: { + all: [], + read: [], + }, + ui: [], + }, + read: { + disabled: true, + savedObject: { + all: [], + read: [], + }, + ui: [], + }, + }, + subFeatures: [ + { + name: 'Require All Spaces Enabled', + requireAllSpaces: true, + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + id: 'test', + name: 'foo', + includeIn: 'none', + ui: ['test-ui'], + savedObject: { + all: [], + read: [], + }, + }, + ], + }, + ], + }, + ], + app: [], + category: { id: 'foo', label: 'foo' }, + }); + + test('returns no error when subfeature requireAllSpaces enabled and all spaces selected', () => { + expect( + validateKibanaPrivileges( + [fooSubFeature], + [ + { + spaces: ['*'], + base: [], + feature: { + foo: ['all', 'test'], + }, + }, + ] + ).validationErrors + ).toEqual([]); + }); + test('returns error when subfeature requireAllSpaces enabled but not all spaces selected', () => { + expect( + validateKibanaPrivileges( + [fooSubFeature], + [ + { + spaces: ['foo-space'], + base: [], + feature: { + foo: ['all', 'test'], + }, + }, + ] + ).validationErrors + ).toEqual([ + 'Sub-feature privilege [Foo - Require All Spaces Enabled] requires all spaces to be selected but received [foo-space]', + ]); + }); }); diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts index 76d90f23a2e83..5b5a602d99ec3 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts @@ -405,7 +405,7 @@ describe('UserProfileService', () => { }); it('retries activation if initially fails with 409 error', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const failureReason = new errors.ResponseError( securityMock.createApiResponse({ statusCode: 409, body: 'some message' }) @@ -449,7 +449,7 @@ describe('UserProfileService', () => { }); it('fails if activation max retries exceeded', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const failureReason = new errors.ResponseError( securityMock.createApiResponse({ statusCode: 409, body: 'some message' }) diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 3aa4fe007a959..078adada6d2b6 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -42,8 +42,8 @@ export const policyIndexPattern = 'metrics-endpoint.policy-*'; export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; // File storage indexes supporting endpoint Upload/download -export const FILE_STORAGE_METADATA_INDEX = '.fleet-files'; -export const FILE_STORAGE_DATA_INDEX = '.fleet-file_data'; +export const FILE_STORAGE_METADATA_INDEX = '.fleet-endpoint-files'; +export const FILE_STORAGE_DATA_INDEX = '.fleet-endpoint-file-data'; // Endpoint API routes export const BASE_ENDPOINT_ROUTE = '/api/endpoint'; @@ -73,6 +73,7 @@ export const GET_FILE_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/get_file`; export const ENDPOINT_ACTION_LOG_ROUTE = `${BASE_ENDPOINT_ROUTE}/action_log/{agent_id}`; export const ACTION_STATUS_ROUTE = `${BASE_ENDPOINT_ROUTE}/action_status`; export const ACTION_DETAILS_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/{action_id}`; +export const ACTION_AGENT_FILE_INFO_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/{action_id}/{agent_id}/file`; export const ACTION_AGENT_FILE_DOWNLOAD_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/{action_id}/{agent_id}/file/download`; export const ENDPOINTS_ACTION_LIST_ROUTE = `${BASE_ENDPOINT_ROUTE}/action`; diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index 868129f3a6737..01ecc95524b27 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -68,6 +68,41 @@ const USERS = [ 'Genevieve', ]; +const toEsSearchHit = ( + hitSource: T, + index: string = 'some-index' +): estypes.SearchHit => { + return { + _index: index, + _id: '123', + _score: 1.0, + _source: hitSource, + }; +}; + +const toEsSearchResponse = ( + hitsSource: Array> +): estypes.SearchResponse => { + return { + took: 3, + timed_out: false, + _shards: { + total: 2, + successful: 2, + skipped: 0, + failed: 0, + }, + hits: { + total: { + value: hitsSource.length, + relation: 'eq', + }, + max_score: 0, + hits: hitsSource, + }, + }; +}; + /** * A generic base class to assist in creating domain specific data generators. It includes * several general purpose random data generators for use within the class and exposes one @@ -193,12 +228,17 @@ export class BaseDataGenerator { hitSource: T, index: string = 'some-index' ): estypes.SearchHit { - return { - _index: index, - _id: this.seededUUIDv4(), - _score: 1.0, - _source: hitSource, - }; + const hit = toEsSearchHit(hitSource, index); + hit._id = this.seededUUIDv4(); + + return hit; + } + + static toEsSearchHit( + hitSource: T, + index: string = 'some-index' + ): estypes.SearchHit { + return toEsSearchHit(hitSource, index); } /** @@ -209,23 +249,12 @@ export class BaseDataGenerator { toEsSearchResponse( hitsSource: Array> ): estypes.SearchResponse { - return { - took: 3, - timed_out: false, - _shards: { - total: 2, - successful: 2, - skipped: 0, - failed: 0, - }, - hits: { - total: { - value: hitsSource.length, - relation: 'eq', - }, - max_score: 0, - hits: hitsSource, - }, - }; + return toEsSearchResponse(hitsSource); + } + + static toEsSearchResponse( + hitsSource: Array> + ): estypes.SearchResponse { + return toEsSearchResponse(hitsSource); } } diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts index e9531e48d0784..f8af9d8005893 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts @@ -88,7 +88,7 @@ export class EndpointActionGenerator extends BaseDataGenerator { output = { type: 'json', content: { - code: 'ra_get-file_success', + code: 'ra_get-file_success_done', path: '/some/path/bad_file.txt', size: 1234, zip_size: 123, diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts index cb9a1d98eb326..310fbcbea326b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts @@ -139,3 +139,13 @@ export const EndpointActionFileDownloadSchema = { export type EndpointActionFileDownloadParams = TypeOf< typeof EndpointActionFileDownloadSchema.params >; + +/** Schema that validates the file info API */ +export const EndpointActionFileInfoSchema = { + params: schema.object({ + action_id: schema.string({ minLength: 1 }), + agent_id: schema.string({ minLength: 1 }), + }), +}; + +export type EndpointActionFileInfoParams = TypeOf; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index 2d455bb6a839f..8ac8745a5d35b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -6,6 +6,7 @@ */ import type { TypeOf } from '@kbn/config-schema'; +import type { FileJSON } from '@kbn/files-plugin/common'; import type { ActionStatusRequestSchema, NoParametersRequestSchema, @@ -360,3 +361,12 @@ export interface ActionListApiResponse { statuses: ResponseActionStatus[] | undefined; total: number; } + +export type UploadedFileInfo = Pick< + FileJSON, + 'name' | 'id' | 'mimeType' | 'size' | 'status' | 'created' +>; + +export interface ActionFileInfoApiResponse { + data: UploadedFileInfo; +} diff --git a/x-pack/plugins/security_solution/common/endpoint/types/file_storage.ts b/x-pack/plugins/security_solution/common/endpoint/types/file_storage.ts deleted file mode 100644 index 9ed8065197921..0000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/types/file_storage.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/** - * The Metadata information about a file that was uploaded by Endpoint - * as a result of a `get-file` response action - */ -export interface UploadedFile { - file: { - /** The chunk size used for each chunk in this file */ - ChunkSize?: number; - /** - * - `AWAITING_UPLOAD`: file metadata has been created. File is ready to be uploaded. - * - `UPLOADING`: file contents are being uploaded. - * - `READY`: file has been uploaded, successfully, without errors. - * - `UPLOAD_ERROR`: an error happened while the file was being uploaded, file contents - * are most likely corrupted. - * - `DELETED`: file is deleted. Files can be marked as deleted before the actual deletion - * of the contents and metadata happens. Deleted files should be treated as if they don’t - * exist. Only files in READY state can transition into DELETED state. - */ - Status: 'AWAITING_UPLOAD' | 'UPLOADING' | 'READY' | 'UPLOAD_ERROR' | 'DELETED'; - /** File extension (if any) */ - extension?: string; - hash?: { - md5?: string; - sha1?: string; - sha256?: string; - sha384?: string; - sha512?: string; - ssdeep?: string; - tlsh?: string; - }; - mime_type?: string; - mode?: string; - /** File name */ - name: string; - /** The full path to the file on the host machine */ - path: string; - /** The total size in bytes */ - size: number; - created?: string; - type: string; - }; -} diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts index cefd43fe5f99e..2c1743e262ead 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts @@ -9,10 +9,13 @@ import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/data-plugin/commo import type { ESQuery } from '../../../../typed_json'; import type { Inspect, Maybe, SortField, TimerangeInput } from '../../../common'; +import type { RiskScoreEntity } from '../common'; export interface RiskScoreRequestOptions extends IEsSearchRequest { defaultIndex: string[]; + riskScoreEntity: RiskScoreEntity; timerange?: TimerangeInput; + includeAlertsCount?: boolean; onlyLatest?: boolean; pagination?: { cursorStart: number; @@ -47,6 +50,7 @@ export interface HostRiskScore { name: string; risk: RiskStats; }; + alertsCount?: number; } export interface UserRiskScore { @@ -55,6 +59,7 @@ export interface UserRiskScore { name: string; risk: RiskStats; }; + alertsCount?: number; } export interface RuleRisk { @@ -73,6 +78,7 @@ export const enum RiskScoreFields { userName = 'user.name', userRiskScore = 'user.risk.calculated_score_norm', userRisk = 'user.risk.calculated_level', + alertsCount = 'alertsCount', } export interface RiskScoreItem { @@ -85,6 +91,8 @@ export interface RiskScoreItem { [RiskScoreFields.hostRiskScore]: Maybe; [RiskScoreFields.userRiskScore]: Maybe; + + [RiskScoreFields.alertsCount]: Maybe; } export const enum RiskSeverity { diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.test.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.test.tsx index 67d9be1817549..2be5960d92a32 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.test.tsx @@ -58,7 +58,7 @@ describe('DraggableWrapper', () => { const mount = useMountAppended(); beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterEach(() => { @@ -66,7 +66,9 @@ describe('DraggableWrapper', () => { if (portal != null) { portal.innerHTML = ''; } + }); + afterAll(() => { jest.useRealTimers(); }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx index 9483c549485de..ee16179c9c735 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx @@ -165,7 +165,7 @@ export const MlPopover = React.memo(() => { rel="noopener noreferrer" target="_blank" > - {'Anomaly Detection with Machine Learning'} + {i18n.ANOMALY_DETECTION_DOCS} ), }} diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts index 2fa1178060005..960734936c1dd 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts @@ -39,5 +39,12 @@ export const MODULE_NOT_COMPATIBLE_TITLE = (incompatibleJobCount: number) => i18n.translate('xpack.securitySolution.components.mlPopup.moduleNotCompatibleTitle', { values: { incompatibleJobCount }, defaultMessage: - '{incompatibleJobCount} {incompatibleJobCount, plural, =1 {job} other {jobs}} are currently unavailable', + '{incompatibleJobCount} {incompatibleJobCount, plural, =1 {job is} other {jobs are}} currently unavailable', }); + +export const ANOMALY_DETECTION_DOCS = i18n.translate( + 'xpack.securitySolution.entityAnalytics.anomalies.AnomalyDetectionDocsTitle', + { + defaultMessage: 'Anomaly Detection with Machine Learning', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx index 6712782b5d7b1..209c0a5ace404 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx @@ -21,11 +21,11 @@ import { } from './helpers'; import { SourcererScopeName } from '../../store/sourcerer/model'; -/** the following `TimelineId`s are detection alert tables */ -const detectionAlertsTimelines = [TableId.alertsOnAlertsPage, TableId.alertsOnRuleDetailsPage]; +/** the following scopes are detection alert tables */ +const detectionAlertsTables = [TableId.alertsOnAlertsPage, TableId.alertsOnRuleDetailsPage]; -/** the following `TimelineId`s are NOT detection alert tables */ -const otherTimelines = [ +/** the following scopes are NOT detection alert tables */ +const otherScopes = [ TableId.hostsPageEvents, TableId.hostsPageSessions, TableId.networkPageEvents, @@ -36,7 +36,7 @@ const otherTimelines = [ TableId.kubernetesPageSessions, ]; -const othersWithoutActive = otherTimelines.filter((x) => x !== TimelineId.active); +const othersWithoutActive = otherScopes.filter((x) => x !== TimelineId.active); const hostNameFilter: Filter = { meta: { @@ -169,13 +169,13 @@ describe('getOptions', () => { }); describe('isDetectionsAlertsTable', () => { - detectionAlertsTimelines.forEach((tableId) => + detectionAlertsTables.forEach((tableId) => test(`it returns true for detections alerts table '${tableId}'`, () => { expect(isDetectionsAlertsTable(tableId)).toEqual(true); }) ); - otherTimelines.forEach((tableId) => + otherScopes.forEach((tableId) => test(`it returns false for (NON alert table) timeline '${tableId}'`, () => { expect(isDetectionsAlertsTable(tableId)).toEqual(false); }) @@ -183,7 +183,7 @@ describe('isDetectionsAlertsTable', () => { }); describe('shouldIgnoreAlertFilters', () => { - detectionAlertsTimelines.forEach((tableId) => { + detectionAlertsTables.forEach((tableId) => { test(`it returns true when the view is 'raw' for detections alerts table '${tableId}'`, () => { const view = 'raw'; expect(shouldIgnoreAlertFilters({ tableId, view })).toEqual(true); @@ -195,7 +195,7 @@ describe('shouldIgnoreAlertFilters', () => { }); }); - otherTimelines.forEach((tableId) => { + otherScopes.forEach((tableId) => { test(`it returns false when the view is 'raw' for (NON alert table) timeline'${tableId}'`, () => { const view = 'raw'; expect(shouldIgnoreAlertFilters({ tableId, view })).toEqual(false); @@ -209,7 +209,7 @@ describe('shouldIgnoreAlertFilters', () => { }); describe('removeIgnoredAlertFilters', () => { - detectionAlertsTimelines.forEach((tableId) => { + detectionAlertsTables.forEach((tableId) => { test(`it removes the ignored alert filters when the view is 'raw' for detections alerts table '${tableId}'`, () => { const view = 'raw'; expect(removeIgnoredAlertFilters({ filters: allFilters, tableId, view })).toEqual([ @@ -223,7 +223,7 @@ describe('removeIgnoredAlertFilters', () => { }); }); - otherTimelines.forEach((tableId) => { + otherScopes.forEach((tableId) => { test(`it does NOT remove any filters when the view is 'raw' for (NON alert table) '${tableId}'`, () => { const view = 'alert'; expect(removeIgnoredAlertFilters({ filters: allFilters, tableId, view })).toEqual(allFilters); @@ -237,7 +237,7 @@ describe('removeIgnoredAlertFilters', () => { }); describe('getSourcererScopeName', () => { - detectionAlertsTimelines.forEach((tableId) => { + detectionAlertsTables.forEach((tableId) => { test(`it returns the 'default' SourcererScopeName when the view is 'raw' for detections alerts table '${tableId}'`, () => { const view = 'raw'; expect(getSourcererScopeName({ scopeId: tableId, view })).toEqual(SourcererScopeName.default); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/__snapshots__/kpi_user_authentications_area.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/__snapshots__/kpi_user_authentications_area.test.ts.snap index 1dcaab239de8e..e6560a8f2c33d 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/__snapshots__/kpi_user_authentications_area.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/__snapshots__/kpi_user_authentications_area.test.ts.snap @@ -7,17 +7,17 @@ Object { Object { "id": "security-solution-my-test", "name": "indexpattern-datasource-current-indexpattern", - "type": "{dataViewId}", + "type": "index-pattern", }, Object { "id": "security-solution-my-test", "name": "indexpattern-datasource-layer-31213ae3-905b-4e88-b987-0cccb1f3209f", - "type": "{dataViewId}", + "type": "index-pattern", }, Object { "id": "security-solution-my-test", "name": "indexpattern-datasource-layer-4590dafb-4ac7-45aa-8641-47a3ff0b817c", - "type": "{dataViewId}", + "type": "index-pattern", }, ], "state": Object { diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.ts index da6bdf139a1ca..ce7be2aa9f369 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/users/kpi_user_authentications_area.ts @@ -183,18 +183,18 @@ export const kpiUserAuthenticationsAreaLensAttributes: LensAttributes = { }, references: [ { - type: '{dataViewId}', - id: 'security-solution-default', + type: 'index-pattern', + id: '{dataViewId}', name: 'indexpattern-datasource-current-indexpattern', }, { - type: '{dataViewId}', - id: 'security-solution-default', + type: 'index-pattern', + id: '{dataViewId}', name: 'indexpattern-datasource-layer-31213ae3-905b-4e88-b987-0cccb1f3209f', }, { - type: '{dataViewId}', - id: 'security-solution-default', + type: 'index-pattern', + id: '{dataViewId}', name: 'indexpattern-datasource-layer-4590dafb-4ac7-45aa-8641-47a3ff0b817c', }, ], diff --git a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.test.ts b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.test.ts index bb65e5def2792..dba14afd0ff2e 100644 --- a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.test.ts +++ b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.test.ts @@ -10,8 +10,16 @@ import { useKibana } from '../../lib/kibana'; import { useMatrixHistogram, useMatrixHistogramCombined } from '.'; import { MatrixHistogramType } from '../../../../common/search_strategy'; import { TestProviders } from '../../mock/test_providers'; +import { useTrackHttpRequest } from '../../lib/apm/use_track_http_request'; jest.mock('../../lib/kibana'); +jest.mock('../../lib/apm/use_track_http_request'); + +const mockEndTracking = jest.fn(); +const mockStartTracking = jest.fn(() => ({ endTracking: mockEndTracking })); +(useTrackHttpRequest as jest.Mock).mockReturnValue({ + startTracking: mockStartTracking, +}); const basicResponse = { isPartial: false, @@ -42,7 +50,7 @@ describe('useMatrixHistogram', () => { }; afterEach(() => { - (useKibana().services.data.search.search as jest.Mock).mockClear(); + jest.clearAllMocks(); }); it('should update request when props has changed', async () => { @@ -156,6 +164,58 @@ describe('useMatrixHistogram', () => { act(() => rerender()); expect(abortSpy).toHaveBeenCalledTimes(3); }); + + describe('trackHttpRequest', () => { + it('should start tracking when request starts', () => { + renderHook(useMatrixHistogram, { + initialProps: props, + wrapper: TestProviders, + }); + + expect(mockStartTracking).toHaveBeenCalledWith({ + name: `securitySolutionUI matrixHistogram ${MatrixHistogramType.events}`, + }); + }); + + it('should end tracking success when the request succeeds', () => { + (useKibana().services.data.search.search as jest.Mock).mockReturnValueOnce({ + subscribe: ({ next }: { next: Function }) => next(basicResponse), + }); + + renderHook(useMatrixHistogram, { + initialProps: props, + wrapper: TestProviders, + }); + + expect(mockEndTracking).toHaveBeenCalledWith('success'); + }); + + it('should end tracking error when the partial request is invalid', () => { + (useKibana().services.data.search.search as jest.Mock).mockReturnValueOnce({ + subscribe: ({ next }: { next: Function }) => next(null), + }); + + renderHook(useMatrixHistogram, { + initialProps: props, + wrapper: TestProviders, + }); + + expect(mockEndTracking).toHaveBeenCalledWith('invalid'); + }); + + it('should end tracking error when the request fails', () => { + (useKibana().services.data.search.search as jest.Mock).mockReturnValueOnce({ + subscribe: ({ error }: { error: Function }) => error('some error'), + }); + + renderHook(useMatrixHistogram, { + initialProps: props, + wrapper: TestProviders, + }); + + expect(mockEndTracking).toHaveBeenCalledWith('error'); + }); + }); }); describe('useMatrixHistogramCombined', () => { diff --git a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts index c770713b602b7..85512855580c3 100644 --- a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts +++ b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts @@ -28,6 +28,8 @@ import { getInspectResponse } from '../../../helpers'; import type { InspectResponse } from '../../../types'; import * as i18n from './translations'; import { useAppToasts } from '../../hooks/use_app_toasts'; +import { useTrackHttpRequest } from '../../lib/apm/use_track_http_request'; +import { APP_UI_ID } from '../../../../common/constants'; export type Buckets = Array<{ key: string; @@ -71,6 +73,7 @@ export const useMatrixHistogram = ({ const abortCtrl = useRef(new AbortController()); const searchSubscription$ = useRef(new Subscription()); const [loading, setLoading] = useState(false); + const { startTracking } = useTrackHttpRequest(); const [matrixHistogramRequest, setMatrixHistogramRequest] = useState({ @@ -102,11 +105,14 @@ export const useMatrixHistogram = ({ buckets: [], }); - const hostsSearch = useCallback( + const search = useCallback( (request: MatrixHistogramRequestOptions) => { const asyncSearch = async () => { abortCtrl.current = new AbortController(); setLoading(true); + const { endTracking } = startTracking({ + name: `${APP_UI_ID} matrixHistogram ${histogramType}`, + }); searchSubscription$.current = data.search .search(request, { @@ -130,10 +136,12 @@ export const useMatrixHistogram = ({ totalCount: histogramBuckets.reduce((acc, bucket) => bucket.doc_count + acc, 0), buckets: histogramBuckets, })); + endTracking('success'); searchSubscription$.current.unsubscribe(); } else if (isErrorResponse(response)) { setLoading(false); addWarning(i18n.ERROR_MATRIX_HISTOGRAM); + endTracking('invalid'); searchSubscription$.current.unsubscribe(); } }, @@ -142,6 +150,7 @@ export const useMatrixHistogram = ({ addError(msg, { title: errorMessage ?? i18n.FAIL_MATRIX_HISTOGRAM, }); + endTracking('error'); searchSubscription$.current.unsubscribe(); }, }); @@ -151,7 +160,7 @@ export const useMatrixHistogram = ({ asyncSearch(); refetch.current = asyncSearch; }, - [data.search, errorMessage, addError, addWarning, histogramType] + [data.search, histogramType, addWarning, addError, errorMessage, startTracking] ); useEffect(() => { @@ -189,13 +198,13 @@ export const useMatrixHistogram = ({ useEffect(() => { // We want to search if it is not skipped, stackByField ends with ip and include missing data if (!skip) { - hostsSearch(matrixHistogramRequest); + search(matrixHistogramRequest); } return () => { searchSubscription$.current.unsubscribe(); abortCtrl.current.abort(); }; - }, [matrixHistogramRequest, hostsSearch, skip]); + }, [matrixHistogramRequest, search, skip]); useEffect(() => { if (skip) { @@ -207,7 +216,7 @@ export const useMatrixHistogram = ({ const runMatrixHistogramSearch = useCallback( (to: string, from: string) => { - hostsSearch({ + search({ ...matrixHistogramRequest, timerange: { interval: '12h', @@ -216,7 +225,7 @@ export const useMatrixHistogram = ({ }, }); }, - [matrixHistogramRequest, hostsSearch] + [matrixHistogramRequest, search] ); return [loading, matrixHistogramResponse, runMatrixHistogramSearch]; diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 967eca53bce1b..20191f7ce312a 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -346,24 +346,26 @@ export const mockGlobalState: State = { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z', }, - sessionViewConfig: null, - show: false, + resolveTimelineConfig: undefined, pinnedEventIds: {}, pinnedEventsSaveObject: {}, - itemsPerPageOptions: [5, 10, 20], + sessionViewConfig: null, + show: false, sort: [ { columnId: '@timestamp', columnType: 'date', esTypes: ['date'], - sortDirection: Direction.desc, + sortDirection: 'desc', }, ], - isSaving: false, + status: TimelineStatus.draft, version: null, - status: TimelineStatus.active, - isSelectAllChecked: false, selectedEventIds: {}, + isSelectAllChecked: false, + filters: [], + isSaving: false, + itemsPerPageOptions: [10, 25, 50, 100], }, }, insertTimeline: null, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx index ec4fdb5cb6e8d..9155415165c5e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx @@ -11,7 +11,7 @@ import { render, screen, fireEvent } from '@testing-library/react'; import { AdditionalFiltersAction } from '.'; import { TestProviders } from '../../../../common/mock/test_providers'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); jest.mock('../../../../common/lib/kibana'); describe('AdditionalFiltersAction', () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.test.ts b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.test.ts index 74f1bb89bb8c5..a4e7baf3c30be 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.test.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.test.ts @@ -7,7 +7,7 @@ import { debounceAsync } from './validators'; -jest.useFakeTimers(); +jest.useFakeTimers('legacy'); describe('debounceAsync', () => { let fn: jest.Mock; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx index 01569edd6907d..52e96c088c200 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx @@ -18,7 +18,6 @@ import { isNewTermsRule, } from '../../../../../common/detection_engine/utils'; import type { FieldHook } from '../../../../shared_imports'; -import { useKibana } from '../../../../common/lib/kibana'; import * as i18n from './translations'; import { MlCardDescription } from './ml_card_description'; @@ -50,9 +49,6 @@ export const SelectRuleType: React.FC = ({ const setThreshold = useCallback(() => setType('threshold'), [setType]); const setThreatMatch = useCallback(() => setType('threat_match'), [setType]); const setNewTerms = useCallback(() => setType('new_terms'), [setType]); - const licensingUrl = useKibana().services.application.getUrlForApp('kibana', { - path: '#/management/stack/license_management', - }); const eqlSelectableConfig = useMemo( () => ({ @@ -130,12 +126,7 @@ export const SelectRuleType: React.FC = ({ data-test-subj="machineLearningRuleType" title={i18n.ML_TYPE_TITLE} titleSize="xs" - description={ - - } + description={} icon={} isDisabled={mlSelectableConfig.isDisabled && !mlSelectableConfig.isSelected} selectable={mlSelectableConfig} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/ml_card_description.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/ml_card_description.tsx index 51ad3e1d83e96..f017bc2d52a8d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/ml_card_description.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/ml_card_description.tsx @@ -13,7 +13,6 @@ import React from 'react'; import { ML_TYPE_DESCRIPTION } from './translations'; interface MlCardDescriptionProps { - subscriptionUrl: string; hasValidLicense?: boolean; } @@ -22,7 +21,6 @@ const SmallText = styled.span` `; const MlCardDescriptionComponent: React.FC = ({ - subscriptionUrl, hasValidLicense = false, }) => ( @@ -34,7 +32,7 @@ const MlCardDescriptionComponent: React.FC = ({ defaultMessage="Access to ML requires a {subscriptionsLink}." values={{ subscriptionsLink: ( - + { }); it('should show long running hint message if pending and >15s have passed', () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); render(); expect(renderResult.queryByTestId('test-longRunningCommandHint')).toBeNull(); @@ -55,7 +55,7 @@ describe('When using CommandExecutionOutput component', () => { }); it('should remove long running hint message if command completes', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); render(); act(() => { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx index 2f8b84c81e038..d69771446038f 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx @@ -22,6 +22,7 @@ import { GET_FILE_ROUTE } from '../../../../../common/endpoint/constants'; import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks'; import type { EndpointPrivileges } from '../../../../../common/endpoint/types'; import { INSUFFICIENT_PRIVILEGES_FOR_COMMAND } from '../../../../common/translations'; +import type { HttpFetchOptionsWithPath } from '@kbn/core-http-browser'; jest.mock('../../../../common/components/user_privileges'); @@ -128,6 +129,19 @@ describe('When using get-file action from response actions console', () => { }); it('should display download link once action completes', async () => { + const actionDetailsApiResponseMock: ReturnType = + { + data: { + ...apiMocks.responseProvider.actionDetails({ + path: '/1', + } as HttpFetchOptionsWithPath).data, + + completedAt: new Date().toISOString(), + command: 'get-file', + }, + }; + apiMocks.responseProvider.actionDetails.mockReturnValue(actionDetailsApiResponseMock); + await render(); enterConsoleCommand(renderResult, 'get-file --path="one/two"'); @@ -135,8 +149,10 @@ describe('When using get-file action from response actions console', () => { expect(apiMocks.responseProvider.actionDetails).toHaveBeenCalled(); }); - expect(renderResult.getByTestId('getFileSuccess').textContent).toEqual( - 'File retrieved from the host.Click here to download(ZIP file passcode: elastic)' - ); + await waitFor(() => { + expect(renderResult.getByTestId('getFileSuccess').textContent).toEqual( + 'File retrieved from the host.Click here to download(ZIP file passcode: elastic)' + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts new file mode 100644 index 0000000000000..dc5c443e15e2e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.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 type { FleetServerAgentComponentUnit } from '@kbn/fleet-plugin/common/types'; + +import { PackageActionFormatter, titles, descriptions } from './package_action_formatter'; +import { ENDPOINT_ERROR_CODES } from '../../../../common/endpoint/constants'; + +describe('PackageActionFormatter', () => { + it('correctly formats es connection error', () => { + const unit: FleetServerAgentComponentUnit = { + id: 'test-id', + type: 'input', + status: 'failed', + message: 'test message', + payload: { + error: { + code: ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR, + message: 'an error message', + }, + }, + }; + const docLinks = { es_connection: 'somedoclink' }; + const formatter = new PackageActionFormatter(unit, docLinks); + expect(formatter.key).toBe('es_connection'); + expect(formatter.title).toBe(titles.get('es_connection')); + expect(formatter.description).toBe(descriptions.get('es_connection')); + expect(formatter.linkUrl).toBe(docLinks.es_connection); + }); + + it('correct formats generic error', () => { + const unit: FleetServerAgentComponentUnit = { + id: 'test-id', + type: 'input', + status: 'failed', + message: 'test message', + }; + const docLinks = { es_connection: 'somedoclink' }; + const formatter = new PackageActionFormatter(unit, docLinks); + expect(formatter.key).toBe('policy_failure'); + expect(formatter.title).toBe(titles.get('policy_failure')); + expect(formatter.description).toBe(descriptions.get('policy_failure')); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts index ac4aebf65c496..9af6983ecfcdb 100644 --- a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts +++ b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts @@ -7,6 +7,10 @@ import { i18n } from '@kbn/i18n'; import type { DocLinks } from '@kbn/doc-links'; +import type { + FleetServerAgentComponentUnit, + FleetServerAgentComponentStatus, +} from '@kbn/fleet-plugin/common/types'; import { ENDPOINT_ERROR_CODES } from '../../../../common/endpoint/constants'; @@ -78,13 +82,12 @@ export class PackageActionFormatter { public linkText?: string; constructor( - code: number, - message: string, + unit: FleetServerAgentComponentUnit, private docLinks: DocLinks['securitySolution']['packageActionTroubleshooting'] ) { - this.key = this.getKeyFromErrorCode(code); + this.key = this.getKeyFromErrorCode(unit.payload?.error?.code, unit.status); this.title = titles.get(this.key) ?? this.key; - this.description = descriptions.get(this.key) || message; + this.description = descriptions.get(this.key) || unit.payload?.error?.message; this.linkText = linkTexts.get(this.key); } @@ -94,10 +97,13 @@ export class PackageActionFormatter { ]; } - private getKeyFromErrorCode(code: number): PackageActions { + private getKeyFromErrorCode( + code: number, + status: FleetServerAgentComponentStatus + ): PackageActions { if (code === ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR) { return 'es_connection'; - } else if (code === 124) { + } else if (status === 'failed') { return 'policy_failure'; } else { throw new Error(`Invalid error code ${code}`); diff --git a/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_wrapper.test.tsx b/x-pack/plugins/security_solution/public/management/components/policy_response/integration_tests/policy_response_wrapper.test.tsx similarity index 93% rename from x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_wrapper.test.tsx rename to x-pack/plugins/security_solution/public/management/components/policy_response/integration_tests/policy_response_wrapper.test.tsx index 3c6d4f66d59cb..f23e3bb005fba 100644 --- a/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_wrapper.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/policy_response/integration_tests/policy_response_wrapper.test.tsx @@ -7,28 +7,26 @@ import React from 'react'; import userEvent from '@testing-library/user-event'; -import type { AppContextTestRender } from '../../../common/mock/endpoint'; -import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; -import type { PolicyResponseWrapperProps } from './policy_response_wrapper'; -import { PolicyResponseWrapper } from './policy_response_wrapper'; -import { HostPolicyResponseActionStatus } from '../../../../common/search_strategy'; -import { useGetEndpointPolicyResponse } from '../../hooks/endpoint/use_get_endpoint_policy_response'; +import type { AppContextTestRender } from '../../../../common/mock/endpoint'; +import { createAppRootMockRenderer } from '../../../../common/mock/endpoint'; +import type { PolicyResponseWrapperProps } from '../policy_response_wrapper'; +import { PolicyResponseWrapper } from '../policy_response_wrapper'; +import { HostPolicyResponseActionStatus } from '../../../../../common/search_strategy'; +import { useGetEndpointPolicyResponse } from '../../../hooks/endpoint/use_get_endpoint_policy_response'; import type { HostPolicyResponse, HostPolicyResponseAppliedAction, -} from '../../../../common/endpoint/types'; -import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; -import { useGetEndpointDetails } from '../../hooks'; +} from '../../../../../common/endpoint/types'; +import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; +import { useGetEndpointDetails } from '../../../hooks'; import { descriptions, LINUX_DEADLOCK_MESSAGE, policyResponseTitles, -} from './policy_response_friendly_names'; +} from '../policy_response_friendly_names'; -jest.setTimeout(10000); - -jest.mock('../../hooks/endpoint/use_get_endpoint_policy_response'); -jest.mock('../../hooks/endpoint/use_get_endpoint_details'); +jest.mock('../../../hooks/endpoint/use_get_endpoint_policy_response'); +jest.mock('../../../hooks/endpoint/use_get_endpoint_details'); describe('when on the policy response', () => { const docGenerator = new EndpointDocGenerator(); diff --git a/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.test.tsx b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.test.tsx new file mode 100644 index 0000000000000..c243687b67378 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.test.tsx @@ -0,0 +1,185 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { AppContextTestRender } from '../../../common/mock/endpoint'; +import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; +import type { + ActionDetails, + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters, +} from '../../../../common/endpoint/types'; +import React from 'react'; +import type { ResponseActionFileDownloadLinkProps } from './response_action_file_download_link'; +import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; +import { + FILE_NO_LONGER_AVAILABLE_MESSAGE, + ResponseActionFileDownloadLink, +} from './response_action_file_download_link'; +import { responseActionsHttpMocks } from '../../mocks/response_actions_http_mocks'; +import { useUserPrivileges as _useUserPrivileges } from '../../../common/components/user_privileges'; +import { getDeferred } from '../../mocks/utils'; +import { waitFor } from '@testing-library/react'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +jest.mock('../../../common/components/user_privileges'); + +describe('When using the `ResponseActionFileDownloadLink` component', () => { + const useUserPrivilegesMock = _useUserPrivileges as jest.Mock< + ReturnType + >; + + let render: () => ReturnType; + let renderResult: ReturnType; + let renderProps: ResponseActionFileDownloadLinkProps; + let apiMocks: ReturnType; + + beforeEach(() => { + const appTestContext = createAppRootMockRenderer(); + + apiMocks = responseActionsHttpMocks(appTestContext.coreStart.http); + + renderProps = { + action: new EndpointActionGenerator('seed').generateActionDetails< + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters + >({ command: 'get-file', completedAt: new Date().toISOString() }), + 'data-test-subj': 'test', + }; + + render = () => { + renderResult = appTestContext.render(); + return renderResult; + }; + }); + + it('should show download button if file is available', () => { + render(); + + expect(renderResult.getByTestId('test-downloadButton')).not.toBeNull(); + expect(renderResult.getByTestId('test-passcodeMessage')).toHaveTextContent( + '(ZIP file passcode: elastic)' + ); + }); + + it('should display custom button label', () => { + renderProps.buttonTitle = 'hello'; + render(); + + expect(renderResult.getByTestId('test-downloadButton')).toHaveTextContent('hello'); + }); + + it('should show loading indicator while calling file info api', async () => { + const deferred = getDeferred(); + + apiMocks.responseProvider.fileInfo.mockDelay.mockReturnValue(deferred.promise); + (renderProps.action as ActionDetails).completedAt = '2021-04-15T16:08:47.449Z'; + + render(); + + expect(renderResult.getByTestId('test-loading')).not.toBeNull(); + + // Release the `file info` api + deferred.resolve(); + + await waitFor(() => { + expect(apiMocks.responseProvider.fileInfo).toHaveBeenCalledWith({ + path: '/api/endpoint/action/123/agent-a/file', + }); + }); + + expect(renderResult.getByTestId('test-downloadButton')).not.toBeNull(); + }); + + it('should show file no longer available message if status is DELETED', async () => { + const fileInfoApiResponseMock = apiMocks.responseProvider.fileInfo(); + + fileInfoApiResponseMock.data.status = 'DELETED'; + apiMocks.responseProvider.fileInfo.mockReturnValue(fileInfoApiResponseMock); + + (renderProps.action as ActionDetails).completedAt = '2021-04-15T16:08:47.449Z'; + + render(); + + await waitFor(() => { + expect(renderResult.getByTestId('test-fileNoLongerAvailable')).toHaveTextContent( + FILE_NO_LONGER_AVAILABLE_MESSAGE + ); + }); + }); + + it('should show file no longer available message if file info api returns 404', async () => { + const error = { message: 'not found', response: { status: 404 } } as IHttpFetchError; + + (renderProps.action as ActionDetails).completedAt = '2021-04-15T16:08:47.449Z'; + apiMocks.responseProvider.fileInfo.mockImplementation(() => { + throw error; + }); + + render(); + + await waitFor(() => { + expect(renderResult.getByTestId('test-fileNoLongerAvailable')).toHaveTextContent( + FILE_NO_LONGER_AVAILABLE_MESSAGE + ); + }); + }); + + it('should show file info API error if one was encountered', async () => { + const error = { message: 'server error', response: { status: 500 } } as IHttpFetchError; + + (renderProps.action as ActionDetails).completedAt = '2021-04-15T16:08:47.449Z'; + apiMocks.responseProvider.fileInfo.mockImplementation(() => { + throw error; + }); + + render(); + + await waitFor(() => { + expect(renderResult.getByTestId('test-apiError')).toHaveTextContent('server error'); + }); + }); + + it('should show nothing if user does not have authz', () => { + const privileges = useUserPrivilegesMock(); + + useUserPrivilegesMock.mockImplementationOnce(() => { + return { + ...privileges, + endpointPrivileges: { + ...privileges.endpointPrivileges, + canWriteFileOperations: false, + }, + }; + }); + + render(); + + expect(apiMocks.responseProvider.fileInfo).not.toHaveBeenCalled(); + expect(renderResult.container.children.length).toBe(0); + }); + + it('should show nothing if action is not complete', () => { + const action = renderProps.action as ActionDetails; + action.completedAt = undefined; + action.isCompleted = false; + + render(); + + expect(apiMocks.responseProvider.fileInfo).not.toHaveBeenCalled(); + expect(renderResult.container.children.length).toBe(0); + }); + + it('should show nothing if action was not successful', () => { + const action = renderProps.action as ActionDetails; + action.wasSuccessful = false; + + render(); + + expect(apiMocks.responseProvider.fileInfo).not.toHaveBeenCalled(); + expect(renderResult.container.children.length).toBe(0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx index 6c01b2284e997..e873a4ce253f7 100644 --- a/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx +++ b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx @@ -6,15 +6,19 @@ */ import type { CSSProperties } from 'react'; -import React, { memo } from 'react'; -import { EuiButtonEmpty, EuiText } from '@elastic/eui'; +import React, { memo, useMemo } from 'react'; +import { EuiButtonEmpty, EuiLoadingContent, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import { resolvePathVariables } from '../../../common/utils/resolve_path_variables'; +import { FormattedError } from '../formatted_error'; +import { useGetFileInfo } from '../../hooks/endpoint/use_get_file_info'; import { useUserPrivileges } from '../../../common/components/user_privileges'; import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; import type { MaybeImmutable } from '../../../../common/endpoint/types'; -import { getHostActionFileDownloadUrl } from '../../services/response_actions/get_host_action_file_download_url'; import type { ActionDetails } from '../../../../common/endpoint/types/actions'; +import { ACTION_AGENT_FILE_DOWNLOAD_ROUTE } from '../../../../common/endpoint/constants'; const STYLE_INHERIT_FONT_FAMILY = Object.freeze({ fontFamily: 'inherit', @@ -25,8 +29,15 @@ const DEFAULT_BUTTON_TITLE = i18n.translate( { defaultMessage: 'Click here to download' } ); +export const FILE_NO_LONGER_AVAILABLE_MESSAGE = i18n.translate( + 'xpack.securitySolution.responseActionFileDownloadLink.fileNoLongerAvailable', + { defaultMessage: 'File is no longer available for download.' } +); + export interface ResponseActionFileDownloadLinkProps { action: MaybeImmutable; + /** If left undefined, the first agent that the action was sent to will be used */ + agentId?: string; buttonTitle?: string; 'data-test-subj'?: string; } @@ -38,18 +49,57 @@ export interface ResponseActionFileDownloadLinkProps { * NOTE: Currently displays only the link for the first host in the Action */ export const ResponseActionFileDownloadLink = memo( - ({ action, buttonTitle = DEFAULT_BUTTON_TITLE, 'data-test-subj': dataTestSubj }) => { + ({ action, agentId, buttonTitle = DEFAULT_BUTTON_TITLE, 'data-test-subj': dataTestSubj }) => { const getTestId = useTestIdGenerator(dataTestSubj); const { canWriteFileOperations } = useUserPrivileges().endpointPrivileges; - if (!canWriteFileOperations) { + // We don't need to call the file info API every time, especially if this component is used from the + // console, where the link is displayed within a short time. So we only do the API call if the + // action was completed more than 2 days ago. + const checkIfStillAvailable = useMemo(() => { + return ( + action.isCompleted && action.wasSuccessful && moment().diff(action.completedAt, 'days') > 2 + ); + }, [action.completedAt, action.isCompleted, action.wasSuccessful]); + + const downloadUrl = useMemo(() => { + return resolvePathVariables(ACTION_AGENT_FILE_DOWNLOAD_ROUTE, { + action_id: action.id, + agent_id: agentId ?? action.agents[0], + }); + }, [action.agents, action.id, agentId]); + + const { + isFetching, + data: fileInfo, + error, + } = useGetFileInfo(action, undefined, { + enabled: canWriteFileOperations && checkIfStillAvailable, + }); + + if (!canWriteFileOperations || !action.isCompleted || !action.wasSuccessful) { return null; } + if (isFetching) { + return ; + } + + // Check if file is no longer available + if ((error && error?.response?.status === 404) || fileInfo?.data.status === 'DELETED') { + return ( + + {FILE_NO_LONGER_AVAILABLE_MESSAGE} + + ); + } else if (error) { + return ; + } + return ( <> { + const actualReactQueryModule = jest.requireActual('@tanstack/react-query'); + + return { + ...actualReactQueryModule, + useQuery: jest.fn((...args) => actualReactQueryModule.useQuery(...args)), + }; +}); + +describe('When using the `useGetFileInfo()` hook', () => { + let renderReactQueryHook: ReactQueryHookRenderer< + Parameters, + ReturnType + >; + let http: AppContextTestRender['coreStart']['http']; + let apiMocks: ReturnType; + let actionDetailsMock: ActionDetails; + + beforeEach(() => { + const testContext = createAppRootMockRenderer(); + + renderReactQueryHook = testContext.renderReactQueryHook as typeof renderReactQueryHook; + http = testContext.coreStart.http; + + apiMocks = responseActionsHttpMocks(http); + + actionDetailsMock = new EndpointActionGenerator('seed').generateActionDetails< + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters + >({ + command: 'get-file', + }); + }); + + it('should call the correct API', async () => { + await renderReactQueryHook(() => useGetFileInfo(actionDetailsMock)); + + expect(apiMocks.responseProvider.fileInfo).toHaveBeenCalledWith({ + path: resolvePathVariables(ACTION_AGENT_FILE_INFO_ROUTE, { + action_id: '123', + agent_id: 'agent-a', + }), + }); + }); + + it('should allow specific agent id to be set on input', async () => { + await renderReactQueryHook(() => useGetFileInfo(actionDetailsMock, 'abc')); + + expect(apiMocks.responseProvider.fileInfo).toHaveBeenCalledWith({ + path: resolvePathVariables(ACTION_AGENT_FILE_INFO_ROUTE, { + action_id: '123', + agent_id: 'abc', + }), + }); + }); + + it('should allow custom options ot be used', async () => { + await renderReactQueryHook(() => + useGetFileInfo(actionDetailsMock, undefined, { + queryKey: ['a', 'b'], + enabled: true, + retry: false, + }) + ); + + expect(useQueryMock).toHaveBeenCalledWith( + expect.objectContaining({ + queryKey: ['a', 'b'], + enabled: true, + retry: false, + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_file_info.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_file_info.ts new file mode 100644 index 0000000000000..c4c2905bfd1f8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_file_info.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { useQuery } from '@tanstack/react-query'; +import { resolvePathVariables } from '../../../common/utils/resolve_path_variables'; +import { useHttp } from '../../../common/lib/kibana/hooks'; +import type { + ActionDetails, + ActionFileInfoApiResponse, + MaybeImmutable, +} from '../../../../common/endpoint/types'; +import { ACTION_AGENT_FILE_INFO_ROUTE } from '../../../../common/endpoint/constants'; + +/** + * Retrieves information about a file that was uploaded by the endpoint as a result of a `get-file` action + * @param action + * @param [agentId] If left undefined, the first agent that the action was sent to will be used + * @param [options] + */ +export const useGetFileInfo = ( + action: MaybeImmutable, + agentId?: string, + options: UseQueryOptions = {} +): UseQueryResult => { + const http = useHttp(); + + return useQuery({ + queryKey: ['get-action-file-info', action.id, agentId ?? action.agents[0]], + ...options, + queryFn: () => { + const apiUrl = resolvePathVariables(ACTION_AGENT_FILE_INFO_ROUTE, { + action_id: action.id, + agent_id: agentId ?? action.agents[0], + }); + + return http.get(apiUrl); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts b/x-pack/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts index bc23427631fb9..52aa80b35586b 100644 --- a/x-pack/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts +++ b/x-pack/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts @@ -17,6 +17,7 @@ import { KILL_PROCESS_ROUTE, SUSPEND_PROCESS_ROUTE, GET_FILE_ROUTE, + ACTION_AGENT_FILE_INFO_ROUTE, } from '../../../common/endpoint/constants'; import type { ResponseProvidersInterface } from '../../common/mock/endpoint/http_handler_mock_factory'; import { httpHandlerMockFactory } from '../../common/mock/endpoint/http_handler_mock_factory'; @@ -29,6 +30,7 @@ import type { GetProcessesActionOutputContent, ResponseActionGetFileOutputContent, ResponseActionGetFileParameters, + ActionFileInfoApiResponse, } from '../../../common/endpoint/types'; export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{ @@ -49,6 +51,8 @@ export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{ processes: () => ActionDetailsApiResponse; getFile: () => ActionDetailsApiResponse; + + fileInfo: () => ActionFileInfoApiResponse; }>; export const responseActionsHttpMocks = httpHandlerMockFactory([ @@ -175,4 +179,21 @@ export const responseActionsHttpMocks = httpHandlerMockFactory { + return { + data: { + created: '2022-10-10T14:57:30.682Z', + id: '123', + mimeType: 'text/plain', + name: 'test.txt', + size: 1234, + status: 'READY', + }, + }; + }, + }, ]); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx index cac9c2a7d0c2c..babb4c78af147 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx @@ -23,11 +23,10 @@ export const EndpointGenericErrorsList = memo( const globalEndpointErrors = useMemo(() => { const errors: PackageActionFormatter[] = []; packageErrors.forEach((unit) => { - if (unit.payload && unit.payload.error) { + if (unit.status === 'failed') { errors.push( new PackageActionFormatter( - unit.payload.error.code, - unit.payload.error.message, + unit, docLinks.links.securitySolution.packageActionTroubleshooting ) ); diff --git a/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.ts b/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.ts deleted file mode 100644 index 5061c6cd36457..0000000000000 --- a/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.ts +++ /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 { resolvePathVariables } from '../../../common/utils/resolve_path_variables'; -import { ACTION_AGENT_FILE_DOWNLOAD_ROUTE } from '../../../../common/endpoint/constants'; -import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types'; - -/** - * get the download URL for a `get-file` action - * @param action - * @param agentId - */ -export const getHostActionFileDownloadUrl = ( - action: MaybeImmutable, - agentId?: string -): string => { - return resolvePathVariables(ACTION_AGENT_FILE_DOWNLOAD_ROUTE, { - action_id: action.id, - agent_id: agentId ?? action.agents[0], - }); -}; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx index 37d5cabca6ce4..b47741a219107 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx @@ -204,4 +204,32 @@ describe('EntityAnalyticsAnomalies', () => { expect(getByTestId('anomalies-table-column-count').textContent).toEqual('Count'); // 'Count' is always rendered by only displayed on mobile }); + + it('renders a warning message when jobs are incompatible', () => { + const jobCount: AnomaliesCount = { + job: { + isInstalled: true, + datafeedState: 'started', + jobState: 'opened', + isCompatible: false, + } as SecurityJob, + name: 'v3_windows_anomalous_script', + count: 0, + entity: AnomalyEntity.User, + }; + + mockUseNotableAnomaliesSearch.mockReturnValue({ + isLoading: false, + data: [jobCount], + refetch: jest.fn(), + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('incompatible_jobs_warnings')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx index beeae25f64b2a..c3333a3e13957 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx @@ -5,9 +5,17 @@ * 2.0. */ import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, EuiPanel } from '@elastic/eui'; +import { + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiInMemoryTable, + EuiPanel, + EuiSpacer, +} from '@elastic/eui'; import { MLJobsAwaitingNodeWarning, ML_PAGES, useMlHref } from '@kbn/ml-plugin/public'; +import { FormattedMessage } from '@kbn/i18n-react'; import { HeaderSection } from '../../../../common/components/header_section'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; import { LastUpdatedAt } from '../../../../common/components/last_updated_at'; @@ -43,7 +51,7 @@ export const ENTITY_ANALYTICS_ANOMALIES_PANEL = 'entity_analytics_anomalies'; export const EntityAnalyticsAnomalies = () => { const { - services: { ml, http }, + services: { ml, http, docLinks }, } = useKibana(); const jobsUrl = useMlHref(ml, http.basePath.get(), { @@ -112,6 +120,11 @@ export const EntityAnalyticsAnomalies = () => { [data] ); + const incompatibleJobCount = useMemo( + () => data.filter(({ job }) => job && !job.isCompatible).length, + [data] + ); + return ( {
+ + {incompatibleJobCount > 0 && ( + <> + +

+ + {i18n.ANOMALY_DETECTION_DOCS} + + ), + }} + /> +

+
+ + + + )} {toggleStatus && ( + i18n.translate('xpack.securitySolution.entityAnalytics.anomalies.moduleNotCompatibleTitle', { + values: { incompatibleJobCount }, + defaultMessage: + '{incompatibleJobCount} {incompatibleJobCount, plural, =1 {job is} other {jobs are}} currently unavailable', + }); + +export const ANOMALY_DETECTION_DOCS = i18n.translate( + 'xpack.securitySolution.entityAnalytics.anomalies.AnomalyDetectionDocsTitle', + { + defaultMessage: 'Anomaly Detection with Machine Learning', + } +); diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx index 055a172e54b73..a19168b5e864b 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx @@ -7,19 +7,28 @@ import React from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiIcon, EuiToolTip } from '@elastic/eui'; +import { EuiLink, EuiIcon, EuiToolTip } from '@elastic/eui'; +import { get } from 'lodash/fp'; import { UsersTableType } from '../../../../users/store/model'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { HostDetailsLink, UserDetailsLink } from '../../../../common/components/links'; import { HostsTableType } from '../../../../hosts/store/model'; import { RiskScore } from '../../../../common/components/severity/common'; -import type { HostRiskScore, RiskSeverity } from '../../../../../common/search_strategy'; +import type { + HostRiskScore, + RiskSeverity, + UserRiskScore, +} from '../../../../../common/search_strategy'; import { RiskScoreEntity, RiskScoreFields } from '../../../../../common/search_strategy'; import * as i18n from './translations'; +import { FormattedCount } from '../../../../common/components/formatted_number'; -type HostRiskScoreColumns = Array>; +type HostRiskScoreColumns = Array>; -export const getRiskScoreColumns = (riskEntity: RiskScoreEntity): HostRiskScoreColumns => [ +export const getRiskScoreColumns = ( + riskEntity: RiskScoreEntity, + openEntityInTimeline: (entityName: string) => void +): HostRiskScoreColumns => [ { field: riskEntity === RiskScoreEntity.host ? 'host.name' : 'user.name', name: i18n.ENTITY_NAME(riskEntity), @@ -75,4 +84,20 @@ export const getRiskScoreColumns = (riskEntity: RiskScoreEntity): HostRiskScoreC return getEmptyTagValue(); }, }, + { + field: RiskScoreFields.alertsCount, + width: '15%', + name: i18n.ALERTS, + truncateText: false, + mobileOptions: { show: true }, + render: (alertCount: number, risk) => ( + openEntityInTimeline(get('host.name', risk) ?? get('user.name', risk))} + > + + + ), + }, ]; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.test.tsx index 89011082a2f81..70faf174ae32f 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.test.tsx @@ -9,6 +9,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { TestProviders } from '../../../../common/mock'; import { EntityAnalyticsRiskScores } from '.'; +import type { UserRiskScore } from '../../../../../common/search_strategy'; import { RiskScoreEntity, RiskSeverity } from '../../../../../common/search_strategy'; import type { SeverityCount } from '../../../../common/components/severity/types'; import { useRiskScore, useRiskScoreKpi } from '../../../../risk_score/containers'; @@ -116,5 +117,38 @@ describe.each([RiskScoreEntity.host, RiskScoreEntity.user])( expect(queryByTestId('entity_analytics_content')).not.toBeInTheDocument(); }); + + it('renders alerts count', () => { + mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() }); + mockUseRiskScoreKpi.mockReturnValue({ + severityCount: mockSeverityCount, + loading: false, + }); + const alertsCount = 999; + const data: UserRiskScore[] = [ + { + '@timestamp': '1234567899', + user: { + name: 'testUsermame', + risk: { + rule_risks: [], + calculated_level: RiskSeverity.high, + calculated_score_norm: 75, + multipliers: [], + }, + }, + alertsCount, + }, + ]; + mockUseRiskScore.mockReturnValue({ ...defaultProps, data }); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('risk-score-alerts')).toHaveTextContent(alertsCount.toString()); + }); } ); diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx index 066c4f29d2787..13899e88f38f9 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { useDispatch } from 'react-redux'; @@ -40,6 +40,7 @@ import { Loader } from '../../../../common/components/loader'; import { Panel } from '../../../../common/components/panel'; import * as commonI18n from '../common/translations'; import { usersActions } from '../../../../users/store'; +import { useNavigateToTimeline } from '../../detection_response/hooks/use_navigate_to_timeline'; const HOST_RISK_TABLE_QUERY_ID = 'hostRiskDashboardTable'; const HOST_RISK_KPI_QUERY_ID = 'headerHostRiskScoreKpiQuery'; @@ -90,8 +91,24 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc [dispatch, riskEntity] ); + const { openHostInTimeline, openUserInTimeline } = useNavigateToTimeline(); + + const openEntityInTimeline = useCallback( + (entityName: string) => { + if (riskEntity === RiskScoreEntity.host) { + openHostInTimeline({ hostName: entityName }); + } else if (riskEntity === RiskScoreEntity.user) { + openUserInTimeline({ userName: entityName }); + } + }, + [riskEntity, openHostInTimeline, openUserInTimeline] + ); + const { toggleStatus, setToggleStatus } = useQueryToggle(entity.tableQueryId); - const columns = useMemo(() => getRiskScoreColumns(riskEntity), [riskEntity]); + const columns = useMemo( + () => getRiskScoreColumns(riskEntity, openEntityInTimeline), + [riskEntity, openEntityInTimeline] + ); const [selectedSeverity, setSelectedSeverity] = useState([]); const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); @@ -146,6 +163,7 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc }, timerange, riskEntity, + includeAlertsCount: true, }); useQueryInspector({ diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts b/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts index 7bb7180712c99..64977ffd5c065 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { MatcherHintOptions } from 'jest-matcher-utils'; + /** * Typescript won't allow global namespace stuff unless you're in a module. * This wouldn't otherwise be a module. The code runs as soon as it's imported. @@ -36,7 +38,7 @@ expect.extend({ ): Promise<{ pass: boolean; message: () => string }> { // Used in printing out the pass or fail message const matcherName = 'toYieldEqualTo'; - const options: jest.MatcherHintOptions = { + const options: MatcherHintOptions = { comment: 'deep equality with any yielded value', isNot: this.isNot, promise: this.promise, @@ -102,7 +104,7 @@ expect.extend({ ): Promise<{ pass: boolean; message: () => string }> { // Used in printing out the pass or fail message const matcherName = 'toYieldObjectEqualTo'; - const options: jest.MatcherHintOptions = { + const options: MatcherHintOptions = { comment: 'subset equality with any yielded value', isNot: this.isNot, promise: this.promise, diff --git a/x-pack/plugins/security_solution/public/risk_score/components/translations.ts b/x-pack/plugins/security_solution/public/risk_score/components/translations.ts index 2016dd1d57990..8d845c6d99987 100644 --- a/x-pack/plugins/security_solution/public/risk_score/components/translations.ts +++ b/x-pack/plugins/security_solution/public/risk_score/components/translations.ts @@ -50,3 +50,7 @@ export const getRiskEntityTranslation = ( return riskEntity === RiskScoreEntity.host ? HOST : USER; }; + +export const ALERTS = i18n.translate('xpack.securitySolution.riskScore.overview.alerts', { + defaultMessage: 'Alerts', +}); diff --git a/x-pack/plugins/security_solution/public/risk_score/containers/all/index.test.tsx b/x-pack/plugins/security_solution/public/risk_score/containers/all/index.test.tsx index c9a8f448c352d..dc2b8dac58493 100644 --- a/x-pack/plugins/security_solution/public/risk_score/containers/all/index.test.tsx +++ b/x-pack/plugins/security_solution/public/risk_score/containers/all/index.test.tsx @@ -168,6 +168,8 @@ describe.each([RiskScoreEntity.host, RiskScoreEntity.user])( expect(mockSearch).toHaveBeenCalledWith({ defaultIndex: [`ml_${riskEntity}_risk_score_latest_default`], factoryQueryType: `${riskEntity}sRiskScore`, + riskScoreEntity: riskEntity, + includeAlertsCount: false, }); }); diff --git a/x-pack/plugins/security_solution/public/risk_score/containers/all/index.tsx b/x-pack/plugins/security_solution/public/risk_score/containers/all/index.tsx index b700f83f7f702..977bc10caecc5 100644 --- a/x-pack/plugins/security_solution/public/risk_score/containers/all/index.tsx +++ b/x-pack/plugins/security_solution/public/risk_score/containers/all/index.tsx @@ -45,6 +45,7 @@ export interface RiskScoreState): RiskScoreState => { const spaceId = useSpaceId(); const defaultIndex = spaceId @@ -158,6 +160,8 @@ export const useRiskScore =
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx index 59579924e3d88..0195e4d5c62f6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { render } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import React from 'react'; import { TestProviders } from '../../../../common/mock'; @@ -15,6 +15,15 @@ import { useGetUserCasesPermissions } from '../../../../common/lib/kibana'; jest.mock('../../../../common/lib/kibana'); const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana'); +jest.mock('@kbn/i18n-react', () => { + const originalModule = jest.requireActual('@kbn/i18n-react'); + const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago'); + + return { + ...originalModule, + FormattedRelative, + }; +}); // Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object // The returned permissions object will indicate that the user does not have permissions by default @@ -30,21 +39,25 @@ jest.mock('../../../../common/hooks/use_resolve_conflict', () => { }); describe('Pane', () => { - test('renders with display block by default', () => { + test('renders with display block by default', async () => { const EmptyComponent = render( ); - expect(EmptyComponent.getByTestId('flyout-pane')).toHaveStyle('display: block'); + await waitFor(() => { + expect(EmptyComponent.getByTestId('flyout-pane')).toHaveStyle('display: block'); + }); }); - test('renders with display none when visibility is set to false', () => { + test('renders with display none when visibility is set to false', async () => { const EmptyComponent = render( ); - expect(EmptyComponent.getByTestId('flyout-pane')).toHaveStyle('display: none'); + await waitFor(() => { + expect(EmptyComponent.getByTestId('flyout-pane')).toHaveStyle('display: none'); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/header_actions.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/header_actions.test.tsx index cd90f1cfb8e7e..a851c90405994 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/header_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/header_actions.test.tsx @@ -15,7 +15,7 @@ import type { ColumnHeaderOptions, HeaderActionProps, } from '../../../../../../common/types/timeline'; -import { TimelineTabs } from '../../../../../../common/types/timeline'; +import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { timelineActions } from '../../../../store/timeline'; import { getColumnHeader } from '../column_headers/helpers'; @@ -35,7 +35,7 @@ jest.mock('../../../../../common/hooks/use_selector', () => ({ })); const columnId = 'test-field'; -const timelineId = 'test-timeline'; +const timelineId = TimelineId.test; /* eslint-disable jsx-a11y/click-events-have-key-events */ mockTriggersActionsUi.getFieldBrowser.mockImplementation( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx index 08484bdb34c95..5807a9667942f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx @@ -7,7 +7,7 @@ import { mount } from 'enzyme'; import React from 'react'; -import { TableId } from '../../../../../../common/types/timeline'; +import { TableId, TimelineId } from '../../../../../../common/types/timeline'; import { TestProviders, mockTimelineModel, mockTimelineData } from '../../../../../common/mock'; import { Actions, isAlert } from '.'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; @@ -97,7 +97,7 @@ const defaultProps = { setEventsLoading: () => {}, showCheckboxes: true, showNotes: false, - timelineId: 'test', + timelineId: TimelineId.test, toggleShowNotes: () => {}, }; @@ -271,7 +271,7 @@ describe('Actions', () => { ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx index 227327fd8e856..e2be31e9d5dd6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx @@ -19,6 +19,7 @@ import { HeaderComponent } from '.'; import { getNewSortDirectionOnClick, getNextSortDirection, getSortDirection } from './helpers'; import { Direction } from '../../../../../../../common/search_strategy'; import { useDeepEqualSelector } from '../../../../../../common/hooks/use_selector'; +import { TimelineId } from '../../../../../../../common/types'; const mockDispatch = jest.fn(); jest.mock('react-redux', () => { @@ -48,7 +49,7 @@ describe('Header', () => { sortDirection: Direction.desc, }, ]; - const timelineId = 'test'; + const timelineId = TimelineId.test; beforeEach(() => { (useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: false }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index cffa38e3435b5..32251df6318f2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -18,7 +18,6 @@ import { kibanaObservable, mockGlobalState, mockTimelineData, - mockTimelineModel, SUB_PLUGINS_REDUCER, } from '../../../../common/mock'; import { TestProviders } from '../../../../common/mock/test_providers'; @@ -29,13 +28,14 @@ import type { Props } from '.'; import { StatefulBody } from '.'; import type { Sort } from './sort'; import { getDefaultControlColumn } from './control_columns'; -import { useMountAppended } from '../../../../common/utils/use_mount_appended'; import { timelineActions } from '../../../store/timeline'; import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline'; import { defaultRowRenderers } from './renderers'; import type { State } from '../../../../common/store'; import { createStore } from '../../../../common/store'; import { tGridReducer } from '@kbn/timelines-plugin/public'; +import { mount } from 'enzyme'; +import type { UseFieldBrowserOptionsProps } from '../../fields_browser'; jest.mock('../../../../common/hooks/use_app_toasts'); jest.mock('../../../../common/components/user_privileges', () => { @@ -49,6 +49,11 @@ jest.mock('../../../../common/components/user_privileges', () => { }; }); +const mockUseFieldBrowserOptions = jest.fn(); +jest.mock('../../fields_browser', () => ({ + useFieldBrowserOptions: (props: UseFieldBrowserOptionsProps) => mockUseFieldBrowserOptions(props), +})); + jest.mock('../../../../common/lib/kibana', () => { const originalModule = jest.requireActual('../../../../common/lib/kibana'); const mockCasesContract = jest.requireActual('@kbn/cases-plugin/public/mocks'); @@ -67,6 +72,7 @@ jest.mock('../../../../common/lib/kibana', () => { data: { search: jest.fn(), query: jest.fn(), + dataViews: jest.fn(), }, uiSettings: { get: jest.fn(), @@ -108,11 +114,6 @@ jest.mock('react-redux', () => { }; }); -jest.mock('../../../../common/hooks/use_selector', () => ({ - useShallowEqualSelector: () => mockTimelineModel, - useDeepEqualSelector: () => mockTimelineModel, -})); - jest.mock('../../../../common/components/link_to'); // Prevent Resolver from rendering @@ -129,9 +130,61 @@ jest.mock('../../fields_browser/create_field_button', () => ({ useCreateFieldButton: () => <>, })); -// SKIP: https://github.com/elastic/kibana/issues/143718 -describe.skip('Body', () => { - const mount = useMountAppended(); +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + return { + ...original, + EuiScreenReaderOnly: () => <>, + }; +}); +jest.mock('suricata-sid-db', () => { + return { + db: [], + }; +}); +jest.mock('react-beautiful-dnd', () => { + const original = jest.requireActual('react-beautiful-dnd'); + return { + ...original, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Droppable: ({ children }: { children: any }) => + children( + { + draggableProps: { + style: {}, + }, + innerRef: jest.fn(), + }, + {} + ), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Draggable: ({ children }: { children: any }) => + children( + { + draggableProps: { + style: {}, + }, + innerRef: jest.fn(), + }, + {} + ), + DraggableProvided: () => <>, + DraggableStateSnapshot: () => <>, + DraggingStyle: () => <>, + NotDraggingStyle: () => <>, + }; +}); + +describe('Body', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const getWrapper = async (childrenComponent: JSX.Element, store?: any) => { + const wrapper = mount(childrenComponent, { + wrappingComponent: TestProviders, + wrappingComponentProps: store ?? {}, + }); + await waitFor(() => wrapper.find('[data-test-subj="suricataRefs"]').exists()); + return wrapper; + }; const mockRefetch = jest.fn(); let appToastsMock: jest.Mocked>; @@ -145,8 +198,8 @@ describe.skip('Body', () => { const props: Props = { activePage: 0, browserFields: mockBrowserFields, - data: mockTimelineData, - id: 'timeline-test', + data: [mockTimelineData[0]], + id: TimelineId.test, refetch: mockRefetch, renderCellValue: DefaultCellRenderer, rowRenderers: defaultRowRenderers, @@ -162,58 +215,58 @@ describe.skip('Body', () => { mockDispatch.mockClear(); }); - test('it renders the column headers', () => { - const wrapper = mount( - - - - ); - + test('it renders the column headers', async () => { + const wrapper = await getWrapper(); expect(wrapper.find('[data-test-subj="column-headers"]').first().exists()).toEqual(true); }); - test('it renders the scroll container', () => { - const wrapper = mount( - - - - ); - + test('it renders the scroll container', async () => { + const wrapper = await getWrapper(); expect(wrapper.find('[data-test-subj="timeline-body"]').first().exists()).toEqual(true); }); - test('it renders events', () => { - const wrapper = mount( - - - - ); - + test('it renders events', async () => { + const wrapper = await getWrapper(); expect(wrapper.find('[data-test-subj="events"]').first().exists()).toEqual(true); }); test('it renders a tooltip for timestamp', async () => { + const { storage } = createSecuritySolutionStorageMock(); const headersJustTimestamp = defaultHeaders.filter((h) => h.id === '@timestamp'); - const testProps = { ...props, columnHeaders: headersJustTimestamp }; - const wrapper = mount( - - - + const state: State = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + ...mockGlobalState.timeline.timelineById, + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], + id: TimelineId.test, + columns: headersJustTimestamp, + }, + }, + }, + }; + + const store = createStore( + state, + SUB_PLUGINS_REDUCER, + { dataTable: tGridReducer }, + kibanaObservable, + storage ); - wrapper.update(); - await waitFor(() => { - wrapper.update(); - headersJustTimestamp.forEach(() => { - expect( - wrapper - .find('[data-test-subj="data-driven-columns"]') - .first() - .find('[data-test-subj="localized-date-tool-tip"]') - .exists() - ).toEqual(true); - }); + const wrapper = await getWrapper(, { store }); + + headersJustTimestamp.forEach(() => { + expect( + wrapper + .find('[data-test-subj="data-driven-columns"]') + .first() + .find('[data-test-subj="localized-date-tool-tip"]') + .exists() + ).toEqual(true); }); - }, 20000); + }); }); describe('action on event', () => { const addaNoteToEvent = (wrapper: ReturnType, note: string) => { @@ -231,14 +284,11 @@ describe.skip('Body', () => { mockDispatch.mockClear(); }); - test('Add a note to an event', () => { - const wrapper = mount( - - - - ); - addaNoteToEvent(wrapper, 'hello world'); + test('Add a note to an event', async () => { + const wrapper = await getWrapper(); + addaNoteToEvent(wrapper, 'hello world'); + wrapper.update(); expect(mockDispatch).toHaveBeenNthCalledWith( 3, expect.objectContaining({ @@ -263,7 +313,7 @@ describe.skip('Body', () => { ); }); - test('Add two notes to an event', () => { + test('Add two notes to an event', async () => { const { storage } = createSecuritySolutionStorageMock(); const state: State = { ...mockGlobalState, @@ -288,13 +338,10 @@ describe.skip('Body', () => { storage ); - const Proxy = (proxyProps: Props) => ( - - - - ); + const Proxy = (proxyProps: Props) => ; + + const wrapper = await getWrapper(, { store }); - const wrapper = mount(); addaNoteToEvent(wrapper, 'hello world'); mockDispatch.mockClear(); addaNoteToEvent(wrapper, 'new hello world'); @@ -328,11 +375,7 @@ describe.skip('Body', () => { mockDispatch.mockReset(); }); test('call the right reduce action to show event details for query tab', async () => { - const wrapper = mount( - - - - ); + const wrapper = await getWrapper(); wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); wrapper.update(); @@ -353,11 +396,7 @@ describe.skip('Body', () => { }); test('call the right reduce action to show event details for pinned tab', async () => { - const wrapper = mount( - - - - ); + const wrapper = await getWrapper(); wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); wrapper.update(); @@ -378,11 +417,7 @@ describe.skip('Body', () => { }); test('call the right reduce action to show event details for notes tab', async () => { - const wrapper = mount( - - - - ); + const wrapper = await getWrapper(); wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); wrapper.update(); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx index 10d196596b7ba..ea06fd70bbbf2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { shallow } from 'enzyme'; import { cloneDeep } from 'lodash'; import React from 'react'; @@ -48,6 +48,11 @@ describe('get_column_renderer', () => { let auditd: Ecs; const mount = useMountAppended(); + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="suricataRefs"]').exists()); + return wrapper; + }; beforeEach(() => { nonSuricata = cloneDeep(mockTimelineData[0].ecs); suricata = cloneDeep(mockTimelineData[2].ecs); @@ -68,14 +73,15 @@ describe('get_column_renderer', () => { expect(wrapper).toMatchSnapshot(); }); - test('should render plain row data when it is a non suricata row', () => { + test('should render plain row data when it is a non suricata row', async () => { const rowRenderer = getRowRenderer({ data: nonSuricata, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ data: nonSuricata, isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + + const wrapper = await getWrapper( {row} @@ -83,14 +89,14 @@ describe('get_column_renderer', () => { expect(wrapper.text()).toEqual(''); }); - test('should render a suricata row data when it is a suricata row', () => { + test('should render a suricata row data when it is a suricata row', async () => { const rowRenderer = getRowRenderer({ data: suricata, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ data: suricata, isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {row} @@ -100,7 +106,7 @@ describe('get_column_renderer', () => { ); }); - test('should render a suricata row data if event.category is network_traffic', () => { + test('should render a suricata row data if event.category is network_traffic', async () => { suricata.event = { ...suricata.event, ...{ category: ['network_traffic'] } }; const rowRenderer = getRowRenderer({ data: suricata, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ @@ -108,7 +114,7 @@ describe('get_column_renderer', () => { isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {row} @@ -118,7 +124,7 @@ describe('get_column_renderer', () => { ); }); - test('should render a zeek row data if event.category is network_traffic', () => { + test('should render a zeek row data if event.category is network_traffic', async () => { zeek.event = { ...zeek.event, ...{ category: ['network_traffic'] } }; const rowRenderer = getRowRenderer({ data: zeek, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ @@ -126,7 +132,7 @@ describe('get_column_renderer', () => { isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {row} @@ -136,7 +142,7 @@ describe('get_column_renderer', () => { ); }); - test('should render a system row data if event.category is network_traffic', () => { + test('should render a system row data if event.category is network_traffic', async () => { system.event = { ...system.event, ...{ category: ['network_traffic'] } }; const rowRenderer = getRowRenderer({ data: system, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ @@ -144,7 +150,7 @@ describe('get_column_renderer', () => { isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {row} @@ -154,7 +160,7 @@ describe('get_column_renderer', () => { ); }); - test('should render a auditd row data if event.category is network_traffic', () => { + test('should render a auditd row data if event.category is network_traffic', async () => { auditd.event = { ...auditd.event, ...{ category: ['network_traffic'] } }; const rowRenderer = getRowRenderer({ data: auditd, rowRenderers: defaultRowRenderers }); const row = rowRenderer?.renderRow({ @@ -162,7 +168,7 @@ describe('get_column_renderer', () => { isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {row} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_details.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_details.test.tsx index 2a4e82a183999..38155bad81a83 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_details.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_details.test.tsx @@ -14,6 +14,7 @@ import '../../../../../../common/mock/match_media'; import { TestProviders } from '../../../../../../common/mock/test_providers'; import { useMountAppended } from '../../../../../../common/utils/use_mount_appended'; import { SuricataDetails } from './suricata_details'; +import { waitFor } from '@testing-library/react'; jest.mock('../../../../../../common/lib/kibana'); @@ -30,14 +31,19 @@ jest.mock('../../../../../../common/components/link_to'); describe('SuricataDetails', () => { const mount = useMountAppended(); + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="suricataRefs"]').exists()); // check for presence of query input + return wrapper; + }; describe('rendering', () => { test('it renders the default SuricataDetails', () => { const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); - test('it returns text if the data does contain suricata data', () => { - const wrapper = mount( + test('it returns text if the data does contain suricata data', async () => { + const wrapper = await getWrapper( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_refs.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_refs.tsx index 2300bcfaa5bc2..602ca3ebbd577 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_refs.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_refs.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; import { getLinksFromSignature } from './suricata_links'; @@ -18,21 +18,41 @@ const LinkEuiFlexItem = styled(EuiFlexItem)` LinkEuiFlexItem.displayName = 'LinkEuiFlexItem'; export const SuricataRefs = React.memo<{ signatureId: number }>(({ signatureId }) => { - let comp = <>; - getLinksFromSignature(signatureId).then((links) => { - comp = ( - - {links.map((link) => ( + const [linksFromSignature, setLinksFromSignature] = useState(undefined); + useEffect(() => { + let isSubscribed = true; + async function getLinks() { + if (signatureId != null) { + try { + const links = await getLinksFromSignature(signatureId); + if (isSubscribed && links != null) { + setLinksFromSignature(links); + } + } catch (exc) { + setLinksFromSignature(undefined); + } + } else if (isSubscribed) { + setLinksFromSignature(undefined); + } + } + getLinks(); + return () => { + isSubscribed = false; + }; + }, [signatureId]); + + return ( + + {linksFromSignature && + linksFromSignature.map((link) => ( {link} ))} - - ); - }); - return comp; + + ); }); SuricataRefs.displayName = 'SuricataRefs'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_row_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_row_renderer.test.tsx index 833fd2cff9666..67fb4fe5dfce8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_row_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_row_renderer.test.tsx @@ -8,6 +8,7 @@ import { shallow } from 'enzyme'; import { cloneDeep } from 'lodash/fp'; import React from 'react'; +import { waitFor } from '@testing-library/react'; import { removeExternalLinkText } from '@kbn/securitysolution-io-ts-utils'; import type { Ecs } from '../../../../../../../common/ecs'; @@ -31,16 +32,22 @@ jest.mock('@elastic/eui', () => { jest.mock('../../../../../../common/components/link_to'); describe('suricata_row_renderer', () => { - const mount = useMountAppended(); let nonSuricata: Ecs; let suricata: Ecs; + const mount = useMountAppended(); + + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="suricataRefs"]').exists()); + return wrapper; + }; beforeEach(() => { nonSuricata = cloneDeep(mockTimelineData[0].ecs); suricata = cloneDeep(mockTimelineData[2].ecs); }); - test('renders correctly against snapshot', () => { + test('renders correctly against snapshot', async () => { const children = suricataRowRenderer.renderRow({ data: nonSuricata, isDraggable: true, @@ -59,13 +66,14 @@ describe('suricata_row_renderer', () => { expect(suricataRowRenderer.isInstance(suricata)).toBe(true); }); - test('should render a suricata row', () => { + test('should render a suricata row', async () => { const children = suricataRowRenderer.renderRow({ data: suricata, isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + + const wrapper = await getWrapper( {children} @@ -80,14 +88,14 @@ describe('suricata_row_renderer', () => { ); }); - test('should render a suricata row even if it does not have a suricata signature', () => { + test('should render a suricata row even if it does not have a suricata signature', async () => { delete suricata?.suricata?.eve?.alert?.signature; const children = suricataRowRenderer.renderRow({ data: suricata, isDraggable: true, scopeId: TimelineId.test, }); - const wrapper = mount( + const wrapper = await getWrapper( {children} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.test.tsx index ddcc2df231a00..e27871d4c9018 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.test.tsx @@ -11,6 +11,7 @@ import { TestProviders } from '../../../../common/mock/test_providers'; import { useMountAppended } from '../../../../common/utils/use_mount_appended'; import { DataProviders } from '.'; +import { TimelineId } from '../../../../../common/types'; describe('DataProviders', () => { const mount = useMountAppended(); @@ -54,7 +55,7 @@ describe('DataProviders', () => { test('it may be resized vertically via a resize handle', () => { const wrapper = mount( - + ); @@ -67,7 +68,7 @@ describe('DataProviders', () => { test('it never grows taller than one third (33%) of the view height', () => { const wrapper = mount( - + ); @@ -80,7 +81,7 @@ describe('DataProviders', () => { test('it automatically displays scroll bars when the width or height of the data providers exceeds the drop target', () => { const wrapper = mount( - + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx index 196c2655e6ab0..eeb383f6a2298 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx @@ -17,6 +17,7 @@ import { useMountAppended } from '../../../../common/utils/use_mount_appended'; import { TimelineHeader } from '.'; import { TimelineStatus, TimelineType } from '../../../../../common/types/timeline'; +import { waitFor } from '@testing-library/react'; const mockUiSettingsForFilterManager = coreMock.createStart().uiSettings; @@ -25,6 +26,11 @@ jest.mock('../../../../common/lib/kibana'); describe('Header', () => { const indexPattern = mockIndexPattern; const mount = useMountAppended(); + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()); + return wrapper; + }; const props = { browserFields: {}, dataProviders: mockDataProviders, @@ -48,9 +54,9 @@ describe('Header', () => { expect(wrapper).toMatchSnapshot(); }); - test('it renders the data providers when show is true', () => { + test('it renders the data providers when show is true', async () => { const testProps = { ...props, show: true }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -59,14 +65,14 @@ describe('Header', () => { expect(wrapper.find('[data-test-subj="dataProviders"]').exists()).toEqual(true); }); - test('it renders the unauthorized call out providers', () => { + test('it renders the unauthorized call out providers', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), showCallOutUnauthorizedMsg: true, }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -75,14 +81,14 @@ describe('Header', () => { expect(wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()).toEqual(true); }); - test('it renders the unauthorized call out with correct icon', () => { + test('it renders the unauthorized call out with correct icon', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), showCallOutUnauthorizedMsg: true, }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -93,14 +99,14 @@ describe('Header', () => { ).toEqual('alert'); }); - test('it renders the unauthorized call out with correct message', () => { + test('it renders the unauthorized call out with correct message', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), showCallOutUnauthorizedMsg: true, }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -113,7 +119,7 @@ describe('Header', () => { ); }); - test('it renders the immutable timeline call out providers', () => { + test('it renders the immutable timeline call out providers', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), @@ -121,7 +127,7 @@ describe('Header', () => { status: TimelineStatus.immutable, }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -130,7 +136,7 @@ describe('Header', () => { expect(wrapper.find('[data-test-subj="timelineImmutableCallOut"]').exists()).toEqual(true); }); - test('it renders the immutable timeline call out with correct icon', () => { + test('it renders the immutable timeline call out with correct icon', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), @@ -138,7 +144,7 @@ describe('Header', () => { status: TimelineStatus.immutable, }; - const wrapper = mount( + const wrapper = await getWrapper( @@ -149,7 +155,7 @@ describe('Header', () => { ).toEqual('alert'); }); - test('it renders the immutable timeline call out with correct message', () => { + test('it renders the immutable timeline call out with correct message', async () => { const testProps = { ...props, filterManager: new FilterManager(mockUiSettingsForFilterManager), @@ -157,7 +163,7 @@ describe('Header', () => { status: TimelineStatus.immutable, }; - const wrapper = mount( + const wrapper = await getWrapper( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx index 4926b11cd9b13..ff129689fb5f9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx @@ -14,7 +14,7 @@ import { AddToFavoritesButton, NewTimeline } from './helpers'; import { useCreateTimelineButton } from './use_create_timeline'; import { kibanaObservable, TestProviders } from '../../../../common/mock/test_providers'; import { timelineActions } from '../../../store/timeline'; -import { TimelineStatus, TimelineType } from '../../../../../common/types/timeline'; +import { TimelineId, TimelineStatus, TimelineType } from '../../../../../common/types/timeline'; import { createSecuritySolutionStorageMock, mockGlobalState, @@ -100,7 +100,7 @@ describe('Favorite Button', () => { test('should render favorite button', () => { const wrapper = mount( - + ); @@ -110,7 +110,7 @@ describe('Favorite Button', () => { test('Favorite button should be enabled ', () => { const wrapper = mount( - + ); @@ -123,7 +123,7 @@ describe('Favorite Button', () => { const spy = jest.spyOn(timelineActions, 'updateIsFavorite'); const wrapper = mount( - + ); @@ -142,8 +142,8 @@ describe('Favorite Button', () => { timeline: { ...mockGlobalState.timeline, timelineById: { - test: { - ...mockGlobalState.timeline.timelineById.test, + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], isFavorite: true, }, }, @@ -156,7 +156,7 @@ describe('Favorite Button', () => { ); const wrapper = mount( - + ); @@ -176,8 +176,8 @@ describe('Favorite Button', () => { timeline: { ...mockGlobalState.timeline, timelineById: { - test: { - ...mockGlobalState.timeline.timelineById.test, + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], status: TimelineStatus.immutable, timelineType: TimelineType.template, templateTimelineId: 'mock-template-timeline-id', @@ -193,7 +193,7 @@ describe('Favorite Button', () => { ); const wrapper = mount( - + ); expect( @@ -212,8 +212,8 @@ describe('Favorite Button', () => { timeline: { ...mockGlobalState.timeline, timelineById: { - test: { - ...mockGlobalState.timeline.timelineById.test, + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], status: TimelineStatus.active, timelineType: TimelineType.template, templateTimelineId: 'mock-template-timeline-id', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index cc48a58717eee..c53360cb9168c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -28,6 +28,7 @@ import { mockSourcererScope } from '../../../../common/containers/sourcerer/mock import { Direction } from '../../../../../common/search_strategy'; import { mockCasesContext } from '@kbn/cases-plugin/public/mocks/mock_cases_context'; import * as helpers from '../../../../common/lib/kuery'; +import { waitFor } from '@testing-library/react'; jest.mock('../../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -109,7 +110,11 @@ describe('Timeline', () => { const endDate = '2018-03-24T03:33:52.253Z'; const mount = useMountAppended(); - + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="timelineHeader"]').exists()); + return wrapper; + }; beforeEach(() => { (useTimelineEvents as jest.Mock).mockReturnValue([ false, @@ -162,8 +167,8 @@ describe('Timeline', () => { spyCombineQueries.mockClear(); }); - test('should trim kqlQueryExpression', () => { - mount( + test('should trim kqlQueryExpression', async () => { + await getWrapper( @@ -184,8 +189,8 @@ describe('Timeline', () => { expect(wrapper.find('QueryTabContentComponent')).toMatchSnapshot(); }); - test('it renders the timeline header', () => { - const wrapper = mount( + test('it renders the timeline header', async () => { + const wrapper = await getWrapper( @@ -194,8 +199,8 @@ describe('Timeline', () => { expect(wrapper.find('[data-test-subj="timelineHeader"]').exists()).toEqual(true); }); - test('it renders the timeline table', () => { - const wrapper = mount( + test('it renders the timeline table', async () => { + const wrapper = await getWrapper( @@ -206,7 +211,7 @@ describe('Timeline', () => { ).toEqual(true); }); - test('it does render the timeline table when the source is loading with no events', () => { + test('it does render the timeline table when the source is loading with no events', async () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, loading: true, @@ -214,7 +219,7 @@ describe('Timeline', () => { selectedPatterns: [], missingPatterns: [], }); - const wrapper = mount( + const wrapper = await getWrapper( @@ -226,8 +231,8 @@ describe('Timeline', () => { expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); }); - test('it does NOT render the timeline table when start is empty', () => { - const wrapper = mount( + test('it does NOT render the timeline table when start is empty', async () => { + const wrapper = await getWrapper( @@ -239,8 +244,8 @@ describe('Timeline', () => { expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); }); - test('it does NOT render the timeline table when end is empty', () => { - const wrapper = mount( + test('it does NOT render the timeline table when end is empty', async () => { + const wrapper = await getWrapper( @@ -252,8 +257,8 @@ describe('Timeline', () => { expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); }); - test('it does NOT render the paging footer when you do NOT have any data providers', () => { - const wrapper = mount( + test('it does NOT render the paging footer when you do NOT have any data providers', async () => { + const wrapper = await getWrapper( @@ -262,8 +267,8 @@ describe('Timeline', () => { expect(wrapper.find('[data-test-subj="table-pagination"]').exists()).toEqual(false); }); - it('it shows the timeline footer', () => { - const wrapper = mount( + it('it shows the timeline footer', async () => { + const wrapper = await getWrapper( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx index 773790b4da652..506353a9b7047 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.test.tsx @@ -162,6 +162,7 @@ describe('useSessionView with active timeline and a session id and graph event i height: 1000, sessionEntityId: 'test', loadAlertDetails: mockDetails, + canAccessEndpointManagement: false, }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx index 8b5add5ae73b1..0cb001b6aa3e1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx @@ -34,6 +34,7 @@ import { useGlobalFullScreen, } from '../../../../common/containers/use_full_screen'; import { detectionsTimelineIds } from '../../../containers/helpers'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; import { timelineDefaults } from '../../../store/timeline/defaults'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; @@ -266,6 +267,7 @@ export const useSessionView = ({ }, [scopeId]); const { globalFullScreen } = useGlobalFullScreen(); const { timelineFullScreen } = useTimelineFullScreen(); + const { canAccessEndpointManagement } = useUserPrivileges().endpointPrivileges; const defaults = isTimelineScope(scopeId) ? timelineDefaults : tableDefaults; const { sessionViewConfig, activeTab } = useDeepEqualSelector((state) => ({ @@ -310,9 +312,17 @@ export const useSessionView = ({ loadAlertDetails: openDetailsPanel, isFullScreen: fullScreen, height: heightMinusSearchBar, + canAccessEndpointManagement, }) : null; - }, [fullScreen, openDetailsPanel, sessionView, sessionViewConfig, height]); + }, [ + height, + sessionViewConfig, + sessionView, + openDetailsPanel, + fullScreen, + canAccessEndpointManagement, + ]); return { openDetailsPanel, diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts index 8daeae3a28767..e778a94e90ac9 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts @@ -9,8 +9,8 @@ import type { KbnClient } from '@kbn/test'; import type { Client } from '@elastic/elasticsearch'; import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; import * as cborx from 'cbor-x'; +import { basename } from 'path'; import { getFileDownloadId } from '../../../../common/endpoint/service/response_actions/get_file_download_id'; -import type { UploadedFile } from '../../../../common/endpoint/types/file_storage'; import { checkInFleetAgent } from '../../common/fleet_services'; import { sendEndpointMetadataUpdate } from '../../common/endpoint_metadata_services'; import { FleetActionGenerator } from '../../../../common/endpoint/data_generators/fleet_action_generator'; @@ -181,22 +181,45 @@ export const sendEndpointActionResponse = async ( // For `get-file`, upload a file to ES if (action.command === 'get-file' && !endpointResponse.error) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const filePath = ( + action as ActionDetails + )?.parameters?.path!; + + const fileName = basename(filePath.replace(/\\/g, '/')); + // Index the file's metadata - const fileMeta = await esClient.index({ + const fileMeta = await esClient.index({ index: FILE_STORAGE_METADATA_INDEX, id: getFileDownloadId(action, action.agents[0]), body: { + action_id: action.id, + agent_id: action.agents[0], + contents: [ + { + hash: { + sha256: '8d61673c9d782297b3c774ded4e3d88f31a8869a8f25cf5cdd402ba6822d1d28', + }, + name: fileName ?? 'bad_file.txt', + path: filePath, + size: 4, + type: 'file', + }, + ], file: { - created: new Date().toISOString(), - extension: 'zip', - path: '/some/path/bad_file.txt', - type: 'file', - size: 221, - name: 'bad_file.txt.zip', + attributes: ['archive', 'compressed'], + ChunkSize: 4194304, + Compression: 'deflate', + hash: { + sha256: '8d61673c9d782297b3c774ded4e3d88f31a8869a8f25cf5cdd402ba6822d1d28', + }, mime_type: 'application/zip', + name: 'upload.zip', + size: 125, Status: 'READY', - ChunkSize: 4194304, + type: 'file', }, + source: 'endpoint', }, refresh: 'wait_for', }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.test.ts new file mode 100644 index 0000000000000..fa3c7e392d91e --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.test.ts @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getActionDetailsById as _getActionDetailsById } from '../../services'; +import type { HttpApiTestSetupMock } from '../../mocks'; +import { createHttpApiTestSetupMock } from '../../mocks'; +import type { EndpointActionFileDownloadParams } from '../../../../common/endpoint/schema/actions'; +import { getActionFileInfoRouteHandler, registerActionFileInfoRoute } from './file_info_handler'; +import { ACTION_AGENT_FILE_INFO_ROUTE } from '../../../../common/endpoint/constants'; +import { EndpointAuthorizationError, NotFoundError } from '../../errors'; +import type { ActionDetails } from '../../../../common/endpoint/types'; +import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; +import { getFileInfo as _getFileInfo } from '../../services/actions/action_files'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; + +jest.mock('../../services'); +jest.mock('../../services/actions/action_files'); + +describe('Response Action file info API', () => { + const getActionDetailsById = _getActionDetailsById as jest.Mock; + const getFileInfo = _getFileInfo as jest.Mock; + + let apiTestSetup: HttpApiTestSetupMock; + let httpRequestMock: ReturnType< + HttpApiTestSetupMock['createRequestMock'] + >; + let httpHandlerContextMock: HttpApiTestSetupMock['httpHandlerContextMock']; + let httpResponseMock: HttpApiTestSetupMock['httpResponseMock']; + + beforeEach(() => { + apiTestSetup = createHttpApiTestSetupMock(); + + ({ httpHandlerContextMock, httpResponseMock } = apiTestSetup); + httpRequestMock = apiTestSetup.createRequestMock({ + params: { action_id: '111', agent_id: '222' }, + }); + }); + + describe('#registerActionFileInfoRoute()', () => { + beforeEach(() => { + registerActionFileInfoRoute(apiTestSetup.routerMock, apiTestSetup.endpointAppContextMock); + }); + + it('should register the route', () => { + expect( + apiTestSetup.getRegisteredRouteHandler('get', ACTION_AGENT_FILE_INFO_ROUTE) + ).toBeDefined(); + }); + + it('should error if user has no authz to api', async () => { + const authz = (await httpHandlerContextMock.securitySolution).endpointAuthz; + authz.canWriteFileOperations = false; + + await apiTestSetup.getRegisteredRouteHandler('get', ACTION_AGENT_FILE_INFO_ROUTE)( + httpHandlerContextMock, + httpRequestMock, + httpResponseMock + ); + + expect(httpResponseMock.forbidden).toHaveBeenCalledWith({ + body: expect.any(EndpointAuthorizationError), + }); + }); + }); + + describe('Route handler', () => { + let fileInfoHandler: ReturnType; + let esClientMock: ReturnType; + let action: ActionDetails; + + beforeEach(() => { + esClientMock = apiTestSetup.getEsClientMock(); + action = new EndpointActionGenerator().generateActionDetails({ + id: '111', + agents: ['222'], + }); + fileInfoHandler = getActionFileInfoRouteHandler(apiTestSetup.endpointAppContextMock); + + getActionDetailsById.mockImplementation(async () => { + return action; + }); + + getFileInfo.mockImplementation(async () => { + return { + created: '2022-10-10T14:57:30.682Z', + id: '123', + mimeType: 'text/plain', + name: 'test.txt', + size: 1234, + status: 'READY', + }; + }); + }); + + it('should error if action ID is invalid', async () => { + getActionDetailsById.mockImplementationOnce(async () => { + throw new NotFoundError('not found'); + }); + await fileInfoHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.notFound).toHaveBeenCalled(); + }); + + it('should error if agent id is not in the action', async () => { + action.agents = ['333']; + await fileInfoHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.customError).toHaveBeenCalledWith({ + statusCode: 400, + body: expect.any(CustomHttpRequestError), + }); + }); + + it('should retrieve the file info with correct file id', async () => { + await fileInfoHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(getFileInfo).toHaveBeenCalledWith(esClientMock, expect.anything(), '111.222'); + }); + + it('should respond with expected output', async () => { + await fileInfoHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.ok).toHaveBeenCalledWith({ + body: { + data: { + created: '2022-10-10T14:57:30.682Z', + id: '123', + mimeType: 'text/plain', + name: 'test.txt', + size: 1234, + status: 'READY', + }, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts new file mode 100644 index 0000000000000..e8290d1c3d3b1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RequestHandler } from '@kbn/core/server'; +import { getFileInfo } from '../../services/actions/action_files'; +import { getActionDetailsById } from '../../services'; +import { ACTION_AGENT_FILE_INFO_ROUTE } from '../../../../common/endpoint/constants'; +import type { EndpointAppContext } from '../../types'; +import type { EndpointActionFileInfoParams } from '../../../../common/endpoint/schema/actions'; +import type { + SecuritySolutionRequestHandlerContext, + SecuritySolutionPluginRouter, +} from '../../../types'; +import { EndpointActionFileInfoSchema } from '../../../../common/endpoint/schema/actions'; +import { withEndpointAuthz } from '../with_endpoint_authz'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { getFileDownloadId } from '../../../../common/endpoint/service/response_actions/get_file_download_id'; +import { errorHandler } from '../error_handler'; + +export const getActionFileInfoRouteHandler = ( + endpointContext: EndpointAppContext +): RequestHandler< + EndpointActionFileInfoParams, + unknown, + unknown, + SecuritySolutionRequestHandlerContext +> => { + const logger = endpointContext.logFactory.get('actionFileInfo'); + + return async (context, req, res) => { + const { action_id: actionId, agent_id: agentId } = req.params; + const esClient = (await context.core).elasticsearch.client.asInternalUser; + const endpointMetadataService = endpointContext.service.getEndpointMetadataService(); + + try { + // Ensure action id is valid and that it was sent to the Agent ID requested. + const actionDetails = await getActionDetailsById(esClient, endpointMetadataService, actionId); + + if (!actionDetails.agents.includes(agentId)) { + throw new CustomHttpRequestError(`Action was not sent to agent id [${agentId}]`, 400); + } + + const fileId = getFileDownloadId(actionDetails, agentId); + + return res.ok({ + body: { + data: await getFileInfo(esClient, logger, fileId), + }, + }); + } catch (error) { + return errorHandler(logger, res, error); + } + }; +}; + +export const registerActionFileInfoRoute = ( + router: SecuritySolutionPluginRouter, + endpointContext: EndpointAppContext +) => { + router.get( + { + path: ACTION_AGENT_FILE_INFO_ROUTE, + validate: EndpointActionFileInfoSchema, + options: { authRequired: true, tags: ['access:securitySolution'] }, + }, + withEndpointAuthz( + { all: ['canWriteFileOperations'] }, + endpointContext.logFactory.get('actionFileInfo'), + getActionFileInfoRouteHandler(endpointContext) + ) + ); +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts index a801360772b28..e5b3e90de8878 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { registerActionFileInfoRoute } from './file_info_handler'; import { registerActionFileDownloadRoutes } from './file_download_handler'; import { registerActionDetailsRoutes } from './details'; import type { SecuritySolutionPluginRouter } from '../../../types'; @@ -26,4 +27,5 @@ export function registerActionRoutes( registerActionDetailsRoutes(router, endpointContext); registerActionFileDownloadRoutes(router, endpointContext); registerResponseActionRoutes(router, endpointContext); + registerActionFileInfoRoute(router, endpointContext); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts index 288c8ba043693..ffbe39f0435a5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts @@ -10,27 +10,30 @@ import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mo import type { Logger } from '@kbn/core/server'; import { createEsFileClient as _createEsFileClient } from '@kbn/files-plugin/server'; import { createFileClientMock } from '@kbn/files-plugin/server/mocks'; -import { getFileDownloadStream } from './action_files'; +import { getFileDownloadStream, getFileInfo } from './action_files'; import type { DiagnosticResult } from '@elastic/elasticsearch'; import { errors } from '@elastic/elasticsearch'; import { NotFoundError } from '../../errors'; +import { FILE_STORAGE_DATA_INDEX } from '../../../../common/endpoint/constants'; +import { BaseDataGenerator } from '../../../../common/endpoint/data_generators/base_data_generator'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; jest.mock('@kbn/files-plugin/server'); const createEsFileClient = _createEsFileClient as jest.Mock; describe('Action Files service', () => { - describe('#getFileDownloadStream()', () => { - let loggerMock: Logger; - let esClientMock: ElasticsearchClientMock; - let fileClientMock: ReturnType; + let loggerMock: Logger; + let esClientMock: ElasticsearchClientMock; + let fileClientMock: ReturnType; - beforeEach(() => { - loggerMock = loggingSystemMock.create().get('mock'); - esClientMock = elasticsearchServiceMock.createElasticsearchClient(); - fileClientMock = createFileClientMock(); - createEsFileClient.mockReturnValue(fileClientMock); - }); + beforeEach(() => { + loggerMock = loggingSystemMock.create().get('mock'); + esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + fileClientMock = createFileClientMock(); + createEsFileClient.mockReturnValue(fileClientMock); + }); + describe('#getFileDownloadStream()', () => { it('should return expected output', async () => { await expect(getFileDownloadStream(esClientMock, loggerMock, '123')).resolves.toEqual({ stream: expect.anything(), @@ -51,4 +54,62 @@ describe('Action Files service', () => { ); }); }); + + describe('#getFileInfo()', () => { + let fileChunksEsResponseMock: estypes.SearchResponse; + + beforeEach(() => { + fileChunksEsResponseMock = BaseDataGenerator.toEsSearchResponse([ + BaseDataGenerator.toEsSearchHit({}), + ]); + + esClientMock.search.mockImplementation(async (searchRequest) => { + if (searchRequest && searchRequest.index === FILE_STORAGE_DATA_INDEX) { + return fileChunksEsResponseMock; + } + + return BaseDataGenerator.toEsSearchResponse([]); + }); + }); + + it('should return expected output', async () => { + await expect(getFileInfo(esClientMock, loggerMock, '123')).resolves.toEqual({ + created: '2022-10-10T14:57:30.682Z', + id: '123', + mimeType: 'text/plain', + name: 'test.txt', + size: 1234, + status: 'READY', + }); + }); + + it('should check if file has chunks if status is `READY`', async () => { + fileChunksEsResponseMock = BaseDataGenerator.toEsSearchResponse([]); + + await expect(getFileInfo(esClientMock, loggerMock, '123')).resolves.toEqual({ + created: '2022-10-10T14:57:30.682Z', + id: '123', + mimeType: 'text/plain', + name: 'test.txt', + size: 1234, + status: 'DELETED', + }); + + expect(loggerMock.debug).toHaveBeenCalledWith( + 'File with id [123] has no data chunks. Status will be adjusted to DELETED' + ); + }); + + it('should return a `NotFoundError` if file id is not found', async () => { + fileClientMock.get.mockRejectedValue( + new errors.ResponseError({ + statusCode: 404, + } as DiagnosticResult) + ); + + await expect(getFileInfo(esClientMock, loggerMock, '123')).rejects.toBeInstanceOf( + NotFoundError + ); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts index 5db82681c3572..cb161ac189d59 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts @@ -7,8 +7,11 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { Readable } from 'stream'; +import type { FileClient } from '@kbn/files-plugin/server'; import { createEsFileClient } from '@kbn/files-plugin/server'; import { errors } from '@elastic/elasticsearch'; +import type { SearchTotalHits } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { UploadedFileInfo } from '../../../../common/endpoint/types'; import { NotFoundError } from '../../errors'; import { FILE_STORAGE_DATA_INDEX, @@ -16,6 +19,32 @@ import { } from '../../../../common/endpoint/constants'; import { EndpointError } from '../../../../common/endpoint/errors'; +const getFileClient = (esClient: ElasticsearchClient, logger: Logger): FileClient => { + return createEsFileClient({ + metadataIndex: FILE_STORAGE_METADATA_INDEX, + blobStorageIndex: FILE_STORAGE_DATA_INDEX, + elasticsearchClient: esClient, + logger, + }); +}; + +const getFileRetrievalError = ( + error: Error | errors.ResponseError, + fileId: string +): EndpointError => { + if (error instanceof errors.ResponseError) { + const statusCode = error.statusCode; + + // 404 will be returned if file id is not found -or- index does not exist yet. + // Using the `NotFoundError` error class will result in the API returning a 404 + if (statusCode === 404) { + return new NotFoundError(`File with id [${fileId}] not found`, error); + } + } + + return new EndpointError(`Failed to get file using id [${fileId}]: ${error.message}`, error); +}; + /** * Returns a NodeJS `Readable` data stream to a file * @param esClient @@ -27,14 +56,8 @@ export const getFileDownloadStream = async ( logger: Logger, fileId: string ): Promise<{ stream: Readable; fileName: string; mimeType?: string }> => { - const fileClient = createEsFileClient({ - metadataIndex: FILE_STORAGE_METADATA_INDEX, - blobStorageIndex: FILE_STORAGE_DATA_INDEX, - elasticsearchClient: esClient, - logger, - }); - try { + const fileClient = getFileClient(esClient, logger); const file = await fileClient.get({ id: fileId }); const { name: fileName, mimeType } = file.data; @@ -44,16 +67,69 @@ export const getFileDownloadStream = async ( mimeType, }; } catch (error) { - if (error instanceof errors.ResponseError) { - const statusCode = error.statusCode; + throw getFileRetrievalError(error, fileId); + } +}; - // 404 will be returned if file id is not found -or- index does not exist yet. - // Using the `NotFoundError` error class will result in the API returning a 404 - if (statusCode === 404) { - throw new NotFoundError(`File with id [${fileId}] not found`, error); +/** + * Retrieve information about a file + * + * @param esClient + * @param logger + * @param fileId + */ +export const getFileInfo = async ( + esClient: ElasticsearchClient, + logger: Logger, + fileId: string +): Promise => { + try { + const fileClient = getFileClient(esClient, logger); + const file = await fileClient.get({ id: fileId }); + const { name, id, mimeType, size, status, created } = file.data; + let fileHasChunks: boolean = true; + + if (status === 'READY') { + fileHasChunks = await doesFileHaveChunks(esClient, fileId); + + if (!fileHasChunks) { + logger.debug( + `File with id [${fileId}] has no data chunks. Status will be adjusted to DELETED` + ); } } - throw new EndpointError(`Failed to get file using id [${fileId}]: ${error.message}`, error); + // TODO: add `ttl` to the return payload by retrieving the value from ILM? + + return { + name, + id, + mimeType, + size, + created, + status: fileHasChunks ? status : 'DELETED', + }; + } catch (error) { + throw getFileRetrievalError(error, fileId); } }; + +const doesFileHaveChunks = async ( + esClient: ElasticsearchClient, + fileId: string +): Promise => { + const chunks = await esClient.search({ + index: FILE_STORAGE_DATA_INDEX, + body: { + query: { + term: { + 'bid.keyword': fileId, + }, + }, + // Setting `_source` to false - we don't need the actual document to be returned + _source: false, + }, + }); + + return Boolean((chunks.hits?.total as SearchTotalHits)?.value); +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts index 377c9bc3caf74..920540fd30082 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/utils.test.ts @@ -444,7 +444,7 @@ describe('When using Actions service utilities', () => { outputs: { '456': { content: { - code: 'ra_get-file_success', + code: 'ra_get-file_success_done', path: '/some/path/bad_file.txt', size: 1234, zip_size: 123, diff --git a/x-pack/plugins/security_solution/server/features.ts b/x-pack/plugins/security_solution/server/features.ts index fc3307a650097..64a082eaea9a6 100644 --- a/x-pack/plugins/security_solution/server/features.ts +++ b/x-pack/plugins/security_solution/server/features.ts @@ -185,6 +185,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( subFeatures: experimentalFeatures.endpointRbacEnabled ? [ { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.endpointList.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Endpoint List access.', + } + ), name: i18n.translate('xpack.securitySolution.featureRegistry.subFeatures.endpointList', { defaultMessage: 'Endpoint List', }), @@ -195,7 +202,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeEndpointList`, `${APP_ID}-readEndpointList`], id: 'endpoint_list_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -206,7 +213,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readEndpointList`], id: 'endpoint_list_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -219,6 +226,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.trustedApplications.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Trusted Applications access.', + } + ), name: i18n.translate( 'xpack.securitySolution.featureRegistry.subFeatures.trustedApplications', { @@ -232,7 +246,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeTrustedApplications`, `${APP_ID}-readTrustedApplications`], id: 'trusted_applications_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -243,7 +257,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readTrustedApplications`], id: 'trusted_applications_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -256,6 +270,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.hostIsolationExceptions.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Host Isolation Exceptions access.', + } + ), name: i18n.translate( 'xpack.securitySolution.featureRegistry.subFeatures.hostIsolationExceptions', { @@ -272,7 +293,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( `${APP_ID}-readHostIsolationExceptions`, ], id: 'host_isolation_exceptions_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -283,7 +304,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readHostIsolationExceptions`], id: 'host_isolation_exceptions_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -296,6 +317,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.blockList.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Blocklist access.', + } + ), name: i18n.translate('xpack.securitySolution.featureRegistry.subFeatures.blockList', { defaultMessage: 'Blocklist', }), @@ -306,7 +334,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeBlocklist`, `${APP_ID}-readBlocklist`], id: 'blocklist_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -317,7 +345,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readBlocklist`], id: 'blocklist_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -330,6 +358,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.eventFilters.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Event Filters access.', + } + ), name: i18n.translate('xpack.securitySolution.featureRegistry.subFeatures.eventFilters', { defaultMessage: 'Event Filters', }), @@ -340,7 +375,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeEventFilters`, `${APP_ID}-readEventFilters`], id: 'event_filters_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -351,7 +386,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readEventFilters`], id: 'event_filters_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -364,6 +399,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.policyManagement.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Policy Management access.', + } + ), name: i18n.translate( 'xpack.securitySolution.featureRegistry.subFeatures.policyManagement', { @@ -377,7 +419,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writePolicyManagement`, `${APP_ID}-readPolicyManagement`], id: 'policy_management_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -388,7 +430,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readPolicyManagement`], id: 'policy_management_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -401,6 +443,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.actionsLogManagement.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Actions Log Management access.', + } + ), name: i18n.translate( 'xpack.securitySolution.featureRegistry.subFeatures.actionsLogManagement', { @@ -417,7 +466,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( `${APP_ID}-readActionsLogManagement`, ], id: 'actions_log_management_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -428,7 +477,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-readActionsLogManagement`], id: 'actions_log_management_read', - includeIn: 'read', + includeIn: 'none', name: 'Read', savedObject: { all: [], @@ -441,6 +490,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.hostIsolation.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Host Isolation access.', + } + ), name: i18n.translate('xpack.securitySolution.featureRegistry.subFeatures.hostIsolation', { defaultMessage: 'Host Isolation', }), @@ -451,7 +507,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeHostIsolation`], id: 'host_isolation_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -464,6 +520,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.processOperations.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Process Operations access.', + } + ), name: i18n.translate( 'xpack.securitySolution.featureRegistry.subFeatures.processOperations', { @@ -477,7 +540,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeProcessOperations`], id: 'process_operations_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], @@ -490,6 +553,13 @@ export const getKibanaPrivilegesFeaturePrivileges = ( ], }, { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'xpack.securitySolution.featureRegistry.subFeatures.fileOperations.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for File Operations access.', + } + ), name: i18n.translate('xpack.securitySolution.featureRegistr.subFeatures.fileOperations', { defaultMessage: 'File Operations', }), @@ -500,7 +570,7 @@ export const getKibanaPrivilegesFeaturePrivileges = ( { api: [`${APP_ID}-writeFileOperations`], id: 'file_operations_all', - includeIn: 'all', + includeIn: 'none', name: 'All', savedObject: { all: [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts index 797c45ea45fa2..5f903386ab012 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts @@ -10,72 +10,274 @@ import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import { findExceptionList } from '@kbn/lists-plugin/server/services/exception_lists/find_exception_list'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/rule_management/mocks'; -import { getReferencedExceptionLists } from './gather_referenced_exceptions'; +import { + getReferencedExceptionLists, + parseReferencedExceptionsLists, +} from './gather_referenced_exceptions'; jest.mock('@kbn/lists-plugin/server/services/exception_lists/find_exception_list'); -describe('getReferencedExceptionLists', () => { - let savedObjectsClient: jest.Mocked; +describe('get referenced exceptions', () => { + describe('getReferencedExceptions', () => { + let savedObjectsClient: jest.Mocked; - beforeEach(() => { - savedObjectsClient = savedObjectsClientMock.create(); + beforeEach(() => { + savedObjectsClient = savedObjectsClientMock.create(); - (findExceptionList as jest.Mock).mockResolvedValue({ - data: [ - { + (findExceptionList as jest.Mock).mockResolvedValue({ + data: [ + { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my-list', + namespace_type: 'single', + type: 'detection', + }, + ], + page: 1, + per_page: 20, + total: 1, + }); + jest.clearAllMocks(); + }); + + it('returns empty object if no rules to search', async () => { + const result = await getReferencedExceptionLists({ + rules: [], + savedObjectsClient, + }); + + expect(result).toEqual({}); + }); + + it('returns found referenced exception lists', async () => { + const result = await getReferencedExceptionLists({ + rules: [ + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ], + savedObjectsClient, + }); + + expect(result).toEqual({ + 'my-list': { ...getExceptionListSchemaMock(), id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection', }, - ], - page: 1, - per_page: 20, - total: 1, + }); }); - jest.clearAllMocks(); - }); - it('returns empty object if no rules to search', async () => { - const result = await getReferencedExceptionLists({ - rules: [], - savedObjectsClient, + it('returns found referenced exception lists when first exceptions list is empty array and second list has a value', async () => { + const result = await getReferencedExceptionLists({ + rules: [ + { + ...getImportRulesSchemaMock(), + exceptions_list: [], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ], + savedObjectsClient, + }); + + expect(result).toEqual({ + 'my-list': { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my-list', + namespace_type: 'single', + type: 'detection', + }, + }); }); - expect(result).toEqual({}); - }); + it('returns found referenced exception lists when two rules reference same list', async () => { + const result = await getReferencedExceptionLists({ + rules: [ + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ], + savedObjectsClient, + }); + + expect(result).toEqual({ + 'my-list': { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my-list', + namespace_type: 'single', + type: 'detection', + }, + }); + }); + + it('returns two found referenced exception lists when two rules reference different lists', async () => { + (findExceptionList as jest.Mock).mockResolvedValue({ + data: [ + { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my-list', + namespace_type: 'single', + type: 'detection', + }, + { + ...getExceptionListSchemaMock(), + id: '456', + list_id: 'other-list', + namespace_type: 'single', + type: 'detection', + }, + ], + page: 1, + per_page: 20, + total: 2, + }); + + const result = await getReferencedExceptionLists({ + rules: [ + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '456', list_id: 'other-list', namespace_type: 'single', type: 'detection' }, + ], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ], + savedObjectsClient, + }); + + // the problem with these tests is that they are entirely dependent on + // the result from the saved objects client matching what we put here + // so it essentially just bypasses the code that is not interacting with + // the saved objects client. + expect(result).toEqual({ + 'my-list': { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my-list', + namespace_type: 'single', + type: 'detection', + }, + 'other-list': { + ...getExceptionListSchemaMock(), + id: '456', + list_id: 'other-list', + namespace_type: 'single', + type: 'detection', + }, + }); + }); - it('returns found referenced exception lists', async () => { - const result = await getReferencedExceptionLists({ - rules: [ + it('returns empty object if no referenced exception lists found', async () => { + const result = await getReferencedExceptionLists({ + rules: [], + savedObjectsClient, + }); + + expect(result).toEqual({}); + }); + }); + describe('parseReferencdedExceptionsLists', () => { + it('should return parsed lists when exception lists are not empty', () => { + const res = parseReferencedExceptionsLists([ { ...getImportRulesSchemaMock(), exceptions_list: [ { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, ], }, - ], - savedObjectsClient, + ]); + expect(res).toEqual([[], [{ listId: 'my-list', namespaceType: 'single' }]]); }); - - expect(result).toEqual({ - 'my-list': { - ...getExceptionListSchemaMock(), - id: '123', - list_id: 'my-list', - namespace_type: 'single', - type: 'detection', - }, + it('should return parsed lists when one empty exception list and one non-empty list', () => { + const res = parseReferencedExceptionsLists([ + { + ...getImportRulesSchemaMock(), + exceptions_list: [], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ]); + expect(res).toEqual([[], [{ listId: 'my-list', namespaceType: 'single' }]]); }); - }); - it('returns empty object if no referenced exception lists found', async () => { - const result = await getReferencedExceptionLists({ - rules: [], - savedObjectsClient, + it('should return parsed lists when two non-empty exception lists reference same list', () => { + const res = parseReferencedExceptionsLists([ + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ]); + expect(res).toEqual([ + [], + [ + { listId: 'my-list', namespaceType: 'single' }, + { listId: 'my-list', namespaceType: 'single' }, + ], + ]); }); - expect(result).toEqual({}); + it('should return parsed lists when two non-empty exception lists reference differet lists', () => { + const res = parseReferencedExceptionsLists([ + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '123', list_id: 'my-list', namespace_type: 'single', type: 'detection' }, + ], + }, + { + ...getImportRulesSchemaMock(), + exceptions_list: [ + { id: '456', list_id: 'other-list', namespace_type: 'single', type: 'detection' }, + ], + }, + ]); + expect(res).toEqual([ + [], + [ + { listId: 'my-list', namespaceType: 'single' }, + { listId: 'other-list', namespaceType: 'single' }, + ], + ]); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts index cbf6050b10b1c..6653e8ad54a6e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts @@ -11,29 +11,28 @@ import { getAllListTypes } from '@kbn/lists-plugin/server/services/exception_lis import type { RuleToImport } from '../../../../../../common/detection_engine/rule_management'; /** - * Helper that takes rules, goes through their referenced exception lists and - * searches for them, returning an object with all those found, using list_id as keys - * @param rules {array} - * @param savedObjectsClient {object} - * @returns {Promise} an object with all referenced lists found, using list_id as keys + * splitting out the parsing of the lists from the fetching + * for easier and more compartmentalized testing + * @param rules Array + * @returns [ExceptionListQueryInfo[], ExceptionListQueryInfo[]] */ -export const getReferencedExceptionLists = async ({ - rules, - savedObjectsClient, -}: { - rules: Array; - savedObjectsClient: SavedObjectsClientContract; -}): Promise> => { - const [lists] = rules.reduce((acc, rule) => { - if (!(rule instanceof Error) && rule.exceptions_list != null) { - return [...acc, rule.exceptions_list]; +export const parseReferencedExceptionsLists = ( + rules: Array +): [ExceptionListQueryInfo[], ExceptionListQueryInfo[]] => { + const lists = rules.reduce((acc, rule) => { + if ( + !(rule instanceof Error) && + rule.exceptions_list != null && + rule.exceptions_list.length > 0 + ) { + return [...acc, ...rule.exceptions_list]; } else { return acc; } }, []); - if (lists == null) { - return {}; + if (lists == null || lists.length === 0) { + return [[], []]; } const [agnosticLists, nonAgnosticLists] = lists.reduce< @@ -49,6 +48,23 @@ export const getReferencedExceptionLists = async ({ }, [[], []] ); + return [agnosticLists, nonAgnosticLists]; +}; +/** + * Helper that takes rules, goes through their referenced exception lists and + * searches for them, returning an object with all those found, using list_id as keys + * @param rules {array} + * @param savedObjectsClient {object} + * @returns {Promise} an object with all referenced lists found, using list_id as keys + */ +export const getReferencedExceptionLists = async ({ + rules, + savedObjectsClient, +}: { + rules: Array; + savedObjectsClient: SavedObjectsClientContract; +}): Promise> => { + const [agnosticLists, nonAgnosticLists] = parseReferencedExceptionsLists(rules); return getAllListTypes(agnosticLists, nonAgnosticLists, savedObjectsClient); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts index 551562c6b6e9f..88410e8db204d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts @@ -15,7 +15,7 @@ const esQuery = { describe('wrapScopedClusterClient', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts index 371e49d26db96..4376b8785e0e3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts @@ -25,7 +25,7 @@ const createSearchSourceClientMock = () => { describe('wrapSearchSourceClient', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index df584c8d64e96..dd4993807f7c3 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -343,7 +343,8 @@ export class Plugin implements ISecuritySolutionPlugin { const securitySolutionSearchStrategy = securitySolutionSearchStrategyProvider( depsStart.data, endpointContext, - depsStart.spaces?.spacesService?.getSpaceId + depsStart.spaces?.spacesService?.getSpaceId, + ruleDataClient ); plugins.data.search.registerSearchStrategy( diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.test.ts index 4208ea44937bc..7abc747eb0c82 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.test.ts @@ -8,6 +8,7 @@ import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; import type { HostsRequestOptions } from '../../../../../../common/search_strategy/security_solution'; +import { RiskScoreEntity } from '../../../../../../common/search_strategy/security_solution'; import * as buildQuery from './query.all_hosts.dsl'; import * as buildRiskQuery from '../../risk_score/all/query.risk_score.dsl'; import { allHosts } from '.'; @@ -128,6 +129,7 @@ describe('allHosts search strategy', () => { expect(buildHostsRiskQuery).toHaveBeenCalledWith({ defaultIndex: ['ml_host_risk_score_latest_test-space'], filterQuery: { terms: { 'host.name': [hostName] } }, + riskScoreEntity: RiskScoreEntity.host, }); }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts index fb4a4aa27353b..86a3cfae8b4f3 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts @@ -19,7 +19,11 @@ import type { } from '../../../../../../common/search_strategy/security_solution/hosts'; import type { HostRiskScore } from '../../../../../../common/search_strategy'; -import { getHostRiskIndex, buildHostNamesFilter } from '../../../../../../common/search_strategy'; +import { + RiskScoreEntity, + getHostRiskIndex, + buildHostNamesFilter, +} from '../../../../../../common/search_strategy'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import type { SecuritySolutionFactory } from '../../types'; @@ -116,6 +120,7 @@ async function getHostRiskData( buildRiskScoreQuery({ defaultIndex: [getHostRiskIndex(spaceId)], filterQuery: buildHostNamesFilter(hostNames), + riskScoreEntity: RiskScoreEntity.host, }) ); return hostRiskResponse; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.test.ts new file mode 100644 index 0000000000000..58b2a55bc1594 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.test.ts @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import { riskScore } from '.'; +import type { IEsSearchResponse } from '@kbn/data-plugin/public'; +import { allowedExperimentalValues } from '../../../../../../common/experimental_features'; +import type { + HostRiskScore, + RiskScoreRequestOptions, +} from '../../../../../../common/search_strategy'; +import { RiskScoreEntity, RiskSeverity } from '../../../../../../common/search_strategy'; +import type { EndpointAppContextService } from '../../../../../endpoint/endpoint_app_context_services'; +import type { EndpointAppContext } from '../../../../../endpoint/types'; +import * as buildQuery from './query.risk_score.dsl'; +import { get } from 'lodash/fp'; +import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; +import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; + +export const mockSearchStrategyResponse: IEsSearchResponse = { + rawResponse: { + took: 1, + timed_out: false, + _shards: { + total: 2, + successful: 2, + skipped: 1, + failed: 0, + }, + hits: { + max_score: null, + hits: [ + { + _id: '4', + _index: 'index', + _source: { + '@timestamp': '1234567899', + host: { + name: 'testUsermame', + risk: { + rule_risks: [], + calculated_level: RiskSeverity.high, + calculated_score_norm: 75, + multipliers: [], + }, + }, + }, + }, + ], + }, + }, + isPartial: false, + isRunning: false, + total: 2, + loaded: 2, +}; + +const searchMock = jest.fn(); + +const mockDeps = { + esClient: {} as IScopedClusterClient, + ruleDataClient: { + ...(ruleRegistryMocks.createRuleDataClient('.alerts-security.alerts') as IRuleDataClient), + getReader: jest.fn((_options?: { namespace?: string }) => ({ + search: searchMock, + getDynamicIndexPattern: jest.fn(), + })), + }, + savedObjectsClient: {} as SavedObjectsClientContract, + endpointContext: { + logFactory: { + get: jest.fn().mockReturnValue({ + warn: jest.fn(), + }), + }, + config: jest.fn().mockResolvedValue({}), + experimentalFeatures: { + ...allowedExperimentalValues, + }, + service: {} as EndpointAppContextService, + } as EndpointAppContext, + request: {} as KibanaRequest, +}; + +export const mockOptions: RiskScoreRequestOptions = { + defaultIndex: ['logs-*'], + riskScoreEntity: RiskScoreEntity.host, + includeAlertsCount: true, +}; + +describe('buildRiskScoreQuery search strategy', () => { + const buildKpiRiskScoreQuery = jest.spyOn(buildQuery, 'buildRiskScoreQuery'); + + describe('buildDsl', () => { + test('should build dsl query', () => { + riskScore.buildDsl(mockOptions); + expect(buildKpiRiskScoreQuery).toHaveBeenCalledWith(mockOptions); + }); + }); + + test('should not enhance data when includeAlertsCount is false', async () => { + const result = await riskScore.parse( + { ...mockOptions, includeAlertsCount: false }, + mockSearchStrategyResponse, + mockDeps + ); + + expect(get('data[0].alertsCount', result)).toBeUndefined(); + }); + + test('should enhance data with alerts count', async () => { + const alertsCunt = 9999; + searchMock.mockReturnValue({ + aggregations: { + alertsByEntity: { + buckets: [ + { + key: 'testUsermame', + doc_count: alertsCunt, + }, + ], + }, + }, + }); + + const result = await riskScore.parse(mockOptions, mockSearchStrategyResponse, mockDeps); + + expect(get('data[0].alertsCount', result)).toBe(alertsCunt); + }); +}); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.ts index 0d2c01b735a5f..5e46ac2b4f440 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/all/index.ts @@ -5,12 +5,19 @@ * 2.0. */ -import type { IEsSearchResponse } from '@kbn/data-plugin/common'; +import type { IEsSearchResponse, SearchRequest } from '@kbn/data-plugin/common'; +import { get, getOr } from 'lodash/fp'; + +import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { SecuritySolutionFactory } from '../../types'; import type { RiskScoreRequestOptions, RiskQueries, + BucketItem, + HostRiskScore, + UserRiskScore, } from '../../../../../../common/search_strategy'; +import { RiskScoreEntity } from '../../../../../../common/search_strategy'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { buildRiskScoreQuery } from './query.risk_score.dsl'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; @@ -26,7 +33,14 @@ export const riskScore: SecuritySolutionFactory< return buildRiskScoreQuery(options); }, - parse: async (options: RiskScoreRequestOptions, response: IEsSearchResponse) => { + parse: async ( + options: RiskScoreRequestOptions, + response: IEsSearchResponse, + deps?: { + spaceId?: string; + ruleDataClient?: IRuleDataClient | null; + } + ) => { const inspect = { dsl: [inspectStringifyObject(buildRiskScoreQuery(options))], }; @@ -34,11 +48,65 @@ export const riskScore: SecuritySolutionFactory< const totalCount = getTotalCount(response.rawResponse.hits.total); const hits = response?.rawResponse?.hits?.hits; const data = hits?.map((hit) => hit._source) ?? []; + const nameField = options.riskScoreEntity === RiskScoreEntity.host ? 'host.name' : 'user.name'; + const names = data.map((risk) => get(nameField, risk) ?? ''); + + const enhancedData = + deps && options.includeAlertsCount + ? await enhanceData(data, names, nameField, deps.ruleDataClient, deps.spaceId) + : data; + return { ...response, inspect, totalCount, - data, + data: enhancedData, }; }, }; + +async function enhanceData( + data: Array, + names: string[], + nameField: string, + ruleDataClient?: IRuleDataClient | null, + spaceId?: string +): Promise> { + const ruleDataReader = ruleDataClient?.getReader({ namespace: spaceId }); + const query = getAlertsQueryForEntity(names, nameField); + + const response = await ruleDataReader?.search(query); + const buckets: BucketItem[] = getOr([], 'aggregations.alertsByEntity.buckets', response); + + const alertsCountByEntityName: Record = buckets.reduce( + (acc, { key, doc_count: count }) => ({ + ...acc, + [key]: count, + }), + {} + ); + + return data.map((risk) => ({ + ...risk, + alertsCount: alertsCountByEntityName[get(nameField, risk)] ?? 0, + })); +} + +const getAlertsQueryForEntity = (names: string[], nameField: string): SearchRequest => ({ + size: 0, + query: { + bool: { + filter: [ + { term: { 'kibana.alert.workflow_status': 'open' } }, + { terms: { [nameField]: names } }, + ], + }, + }, + aggs: { + alertsByEntity: { + terms: { + field: nameField, + }, + }, + }, +}); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts index 51529bc21d801..f222e2130ee26 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -11,6 +11,7 @@ import type { SavedObjectsClientContract, } from '@kbn/core/server'; import type { IEsSearchResponse, ISearchRequestParams } from '@kbn/data-plugin/common'; +import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { FactoryQueryTypes, StrategyRequestType, @@ -29,6 +30,7 @@ export interface SecuritySolutionFactory { endpointContext: EndpointAppContext; request: KibanaRequest; spaceId?: string; + ruleDataClient?: IRuleDataClient | null; } ) => Promise>; } diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.test.ts index 1f17bbfc870fc..18bc75edb5304 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.test.ts @@ -14,6 +14,7 @@ import type { UsersRequestOptions } from '../../../../../../common/search_strate import * as buildRiskQuery from '../../risk_score/all/query.risk_score.dsl'; import { get } from 'lodash/fp'; +import { RiskScoreEntity } from '../../../../../../common/search_strategy'; class IndexNotFoundException extends Error { meta: { body: { error: { type: string } } }; @@ -115,6 +116,7 @@ describe('allHosts search strategy', () => { expect(buildHostsRiskQuery).toHaveBeenCalledWith({ defaultIndex: ['ml_user_risk_score_latest_test-space'], filterQuery: { terms: { 'user.name': userName } }, + riskScoreEntity: RiskScoreEntity.user, }); }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts index d5c13e0d2b52e..c936ad85f79e0 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts @@ -23,7 +23,11 @@ import type { import type { AllUsersAggEsItem } from '../../../../../../common/search_strategy/security_solution/users/common'; import { buildRiskScoreQuery } from '../../risk_score/all/query.risk_score.dsl'; import type { RiskSeverity, UserRiskScore } from '../../../../../../common/search_strategy'; -import { buildUserNamesFilter, getUserRiskIndex } from '../../../../../../common/search_strategy'; +import { + RiskScoreEntity, + buildUserNamesFilter, + getUserRiskIndex, +} from '../../../../../../common/search_strategy'; export const allUsers: SecuritySolutionFactory = { buildDsl: (options: UsersRequestOptions) => { @@ -123,6 +127,7 @@ async function getUserRiskData( buildRiskScoreQuery({ defaultIndex: [getUserRiskIndex(spaceId)], filterQuery: buildUserNamesFilter(userNames), + riskScoreEntity: RiskScoreEntity.user, }) ); return userRiskResponse; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts index faee7d6b6d8f3..1acb6687b8ace 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts @@ -10,6 +10,7 @@ import type { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server'; import { shimHitsTotal } from '@kbn/data-plugin/server'; import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import type { KibanaRequest } from '@kbn/core/server'; +import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { FactoryQueryTypes, StrategyResponseType, @@ -33,7 +34,8 @@ function assertValidRequestType( export const securitySolutionSearchStrategyProvider = ( data: PluginStart, endpointContext: EndpointAppContext, - getSpaceId?: (request: KibanaRequest) => string + getSpaceId?: (request: KibanaRequest) => string, + ruleDataClient?: IRuleDataClient | null ): ISearchStrategy, StrategyResponseType> => { const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY); @@ -60,6 +62,7 @@ export const securitySolutionSearchStrategyProvider = &2 echo "Failed to set the reject of queries on Mysql node, exiting."\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo "Successfully stopped accepting queries."\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo "ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections."\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\nType :qa! and press to abandon all changes and exit Vim\u0007\u001b[58;9H\u001b[?25h\u0007\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hqa!\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001bkroot@staging-host:~\u001b\\\n', }, tty: { diff --git a/x-pack/plugins/session_view/common/types/process_tree/index.ts b/x-pack/plugins/session_view/common/types/process_tree/index.ts index 68f8924abd702..b228502f61a54 100644 --- a/x-pack/plugins/session_view/common/types/process_tree/index.ts +++ b/x-pack/plugins/session_view/common/types/process_tree/index.ts @@ -72,6 +72,7 @@ export interface IOLine { export interface ProcessStartMarker { event: ProcessEvent; line: number; + maxBytesExceeded?: boolean; } export interface IOFields { diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index 32cc5dffdea5d..18296992de65f 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -53,6 +53,7 @@ export const SessionView = ({ jumpToCursor, investigatedAlertId, loadAlertDetails, + canAccessEndpointManagement, }: SessionViewDeps) => { // don't engage jumpTo if jumping to session leader. if (jumpToEntityId === sessionEntityId) { @@ -422,6 +423,7 @@ export const SessionView = ({ isFullscreen={isFullScreen} onJumpToEvent={onJumpToEvent} autoSeekToEntityId={currentJumpToOutputEntityId} + canAccessEndpointManagement={canAccessEndpointManagement} />
); diff --git a/x-pack/plugins/session_view/public/components/tty_player/ansi_helpers.ts b/x-pack/plugins/session_view/public/components/tty_player/ansi_helpers.ts new file mode 100644 index 0000000000000..e5ad54f7e5269 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_player/ansi_helpers.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 { Teletype } from '../../../common/types/process_tree'; +import { + PROCESS_DATA_LIMIT_EXCEEDED_START, + PROCESS_DATA_LIMIT_EXCEEDED_END, + VIEW_POLICIES, +} from './translations'; + +export const renderTruncatedMsg = (tty?: Teletype, policiesUrl?: string, processName?: string) => { + if (tty?.columns) { + const lineBreak = '-'.repeat(tty.columns); + const message = ` ⚠ ${PROCESS_DATA_LIMIT_EXCEEDED_START} \x1b[1m${processName}.\x1b[22m ${PROCESS_DATA_LIMIT_EXCEEDED_END}`; + const link = policiesUrl + ? `\x1b[${Math.min( + message.length + 2, + tty.columns - VIEW_POLICIES.length - 4 + )}G\x1b[1m\x1b]8;;${policiesUrl}\x1b\\[ ${VIEW_POLICIES} ]\x1b]8;;\x1b\\\x1b[22m` + : ''; + + return `\n\x1b[33m${lineBreak}\n${message}${link}\n${lineBreak}\x1b[0m\n\n`; + } +}; diff --git a/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx b/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx index 9f7201492520c..b40605ad2cdba 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx @@ -30,7 +30,7 @@ describe('TTYPlayer/hooks', () => { })), }); - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); describe('useIOLines', () => { diff --git a/x-pack/plugins/session_view/public/components/tty_player/hooks.ts b/x-pack/plugins/session_view/public/components/tty_player/hooks.ts index b6891f1dd1d49..30b40beaa094f 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/hooks.ts +++ b/x-pack/plugins/session_view/public/components/tty_player/hooks.ts @@ -12,6 +12,7 @@ import { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { SearchAddon } from './xterm_search'; import { useEuiTheme } from '../../hooks'; +import { renderTruncatedMsg } from './ansi_helpers'; import { IOLine, @@ -103,6 +104,15 @@ export const useIOLines = (pages: ProcessEventsPage[] | undefined) => { newMarkers.push(processLineInfo); } + if (process.io.max_bytes_per_process_exceeded) { + const marker = newMarkers.find( + (item) => item.event.process?.entity_id === process.entity_id + ); + if (marker) { + marker.maxBytesExceeded = true; + } + } + const splitLines = process.io.text.split(TTY_LINE_SPLITTER_REGEX); const combinedLines = [splitLines[0]]; @@ -158,6 +168,7 @@ export interface XtermPlayerDeps { hasNextPage?: boolean; fetchNextPage?: () => void; isFetching?: boolean; + policiesUrl?: string; } export const useXtermPlayer = ({ @@ -169,17 +180,20 @@ export const useXtermPlayer = ({ hasNextPage, fetchNextPage, isFetching, + policiesUrl, }: XtermPlayerDeps) => { const { euiTheme } = useEuiTheme(); const { font, colors } = euiTheme; const [currentLine, setCurrentLine] = useState(0); const [playSpeed] = useState(DEFAULT_TTY_PLAYSPEED_MS); // potentially configurable const tty = lines?.[currentLine]?.event.process?.tty; - + const processName = lines?.[currentLine]?.event.process?.name; const [terminal, searchAddon] = useMemo(() => { const term = new Terminal({ theme: { - selection: colors.warning, + selectionBackground: colors.warning, + selectionForeground: colors.ink, + yellow: colors.warning, }, fontFamily: font.familyCode, fontSize: DEFAULT_TTY_FONT_SIZE, @@ -187,6 +201,8 @@ export const useXtermPlayer = ({ convertEol: true, rows: DEFAULT_TTY_ROWS, cols: DEFAULT_TTY_COLS, + allowProposedApi: true, + allowTransparency: true, }); const searchInstance = new SearchAddon(); @@ -203,7 +219,7 @@ export const useXtermPlayer = ({ // even though we set scrollback: 0 above, xterm steals the wheel events and prevents the outer container from scrolling // this handler fixes that const onScroll = (event: WheelEvent) => { - if ((event?.target as HTMLDivElement)?.className === 'xterm-cursor-layer') { + if ((event?.target as HTMLDivElement)?.offsetParent?.classList.contains('xterm-screen')) { event.stopImmediatePropagation(); } }; @@ -212,6 +228,7 @@ export const useXtermPlayer = ({ return () => { window.removeEventListener('wheel', onScroll, true); + terminal.dispose(); }; }, [terminal, ref]); @@ -241,17 +258,30 @@ export const useXtermPlayer = ({ if (line?.value !== undefined) { terminal.write(line.value); } + + const nextLine = lines[lineNumber + index + 1]; + const maxBytesExceeded = line.event.process?.io?.max_bytes_per_process_exceeded; + + // if next line is start of next event + // and process has exceeded max bytes + // render msg + if (!clear && (!nextLine || nextLine.event !== line.event) && maxBytesExceeded) { + const msg = renderTruncatedMsg(tty, policiesUrl, processName); + if (msg) { + terminal.write(msg); + } + } }); }, - [lines, terminal] + [lines, policiesUrl, processName, terminal, tty] ); useEffect(() => { - const fontChanged = terminal.getOption('fontSize') !== fontSize; + const fontChanged = terminal.options.fontSize !== fontSize; const ttyChanged = tty && (terminal.rows !== tty?.rows || terminal.cols !== tty?.columns); if (fontChanged) { - terminal.setOption('fontSize', fontSize); + terminal.options.fontSize = fontSize; } if (tty?.rows && tty?.columns && ttyChanged) { diff --git a/x-pack/plugins/session_view/public/components/tty_player/index.test.tsx b/x-pack/plugins/session_view/public/components/tty_player/index.test.tsx index f3332ae5bb7f8..ba56931b4a99b 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/index.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player/index.test.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; -import { waitFor } from '@testing-library/react'; +import { waitFor, act } from '@testing-library/react'; import { sessionViewIOEventsMock } from '../../../common/mocks/responses/session_view_io_events.mock'; import { AppContextTestRender, createAppRootMockRenderer } from '../../test'; import { TTYPlayerDeps, TTYPlayer } from '.'; +import userEvent from '@testing-library/user-event'; describe('TTYPlayer component', () => { beforeAll(() => { @@ -81,5 +82,38 @@ describe('TTYPlayer component', () => { await waitForApiCall(); }); + + it('renders a message warning when max_bytes exceeded', async () => { + renderResult = mockedContext.render(); + + await waitForApiCall(); + await new Promise((r) => setTimeout(r, 10)); + + const seekToEndBtn = renderResult.getByTestId('sessionView:TTYPlayerControlsEnd'); + + act(() => { + userEvent.click(seekToEndBtn); + }); + + waitFor(() => expect(renderResult.queryAllByText('Data limit reached')).toHaveLength(1)); + expect(renderResult.queryByText('[ VIEW POLICIES ]')).toBeFalsy(); + }); + + it('renders a message warning when max_bytes exceeded with link to policies page', async () => { + renderResult = mockedContext.render( + + ); + + await waitForApiCall(); + await new Promise((r) => setTimeout(r, 10)); + + const seekToEndBtn = renderResult.getByTestId('sessionView:TTYPlayerControlsEnd'); + + act(() => { + userEvent.click(seekToEndBtn); + }); + + waitFor(() => expect(renderResult.queryAllByText('[ VIEW POLICIES ]')).toHaveLength(1)); + }); }); }); diff --git a/x-pack/plugins/session_view/public/components/tty_player/index.tsx b/x-pack/plugins/session_view/public/components/tty_player/index.tsx index c77efc9d8c152..434805ac689db 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/index.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player/index.tsx @@ -13,6 +13,8 @@ import { EuiButton, EuiBetaBadge, } from '@elastic/eui'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { CoreStart } from '@kbn/core/public'; import useResizeObserver from 'use-resize-observer'; import { throttle } from 'lodash'; import { ProcessEvent } from '../../../common/types/process_tree'; @@ -23,6 +25,8 @@ import { DEFAULT_TTY_ROWS, DEFAULT_TTY_COLS, DEFAULT_TTY_FONT_SIZE, + POLICIES_PAGE_PATH, + SECURITY_APP_ID, } from '../../../common/constants'; import { useFetchIOEvents, useIOLines, useXtermPlayer } from './hooks'; import { TTYPlayerControls } from '../tty_player_controls'; @@ -35,6 +39,7 @@ export interface TTYPlayerDeps { isFullscreen: boolean; onJumpToEvent(event: ProcessEvent): void; autoSeekToEntityId?: string; + canAccessEndpointManagement?: boolean; } export const TTYPlayer = ({ @@ -44,6 +49,7 @@ export const TTYPlayer = ({ isFullscreen, onJumpToEvent, autoSeekToEntityId, + canAccessEndpointManagement, }: TTYPlayerDeps) => { const ref = useRef(null); const { ref: scrollRef, height: containerHeight = 1 } = useResizeObserver({}); @@ -53,7 +59,16 @@ export const TTYPlayer = ({ const { lines, processStartMarkers } = useIOLines(data?.pages); const [fontSize, setFontSize] = useState(DEFAULT_TTY_FONT_SIZE); const [isPlaying, setIsPlaying] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); const [currentAutoSeekEntityId, setCurrentAutoSeekEntityId] = useState(''); + const { getUrlForApp } = useKibana().services.application; + const policiesUrl = useMemo( + () => + canAccessEndpointManagement + ? getUrlForApp(SECURITY_APP_ID, { path: POLICIES_PAGE_PATH }) + : '', + [canAccessEndpointManagement, getUrlForApp] + ); const { search, currentLine, seekToLine } = useXtermPlayer({ ref, @@ -64,6 +79,7 @@ export const TTYPlayer = ({ hasNextPage, fetchNextPage, isFetching, + policiesUrl, }); const currentProcessEvent = lines[Math.min(lines.length - 1, currentLine)]?.event; @@ -113,11 +129,18 @@ export const TTYPlayer = ({ const styles = useStyles(tty, show); + const clearSearch = useCallback(() => { + if (searchQuery) { + setSearchQuery(''); + } + }, [searchQuery]); + const onSeekLine = useMemo(() => { return throttle((line: number) => { + clearSearch(); seekToLine(line); }, 100); - }, [seekToLine]); + }, [clearSearch, seekToLine]); const onTogglePlayback = useCallback(() => { // if at the end, seek to beginning @@ -127,6 +150,12 @@ export const TTYPlayer = ({ setIsPlaying(!isPlaying); }, [currentLine, isPlaying, lines.length, seekToLine]); + useEffect(() => { + if (isPlaying) { + clearSearch(); + } + }, [clearSearch, isPlaying]); + return (
@@ -140,6 +169,8 @@ export const TTYPlayer = ({ seekToLine={seekToLine} xTermSearchFn={search} setIsPlaying={setIsPlaying} + searchQuery={searchQuery} + setSearchQuery={setSearchQuery} /> @@ -157,11 +188,17 @@ export const TTYPlayer = ({ - + - + diff --git a/x-pack/plugins/session_view/public/components/tty_player/translations.ts b/x-pack/plugins/session_view/public/components/tty_player/translations.ts new file mode 100644 index 0000000000000..8d1dfd7497410 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_player/translations.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; + +export const PROCESS_DATA_LIMIT_EXCEEDED_START = i18n.translate( + 'xpack.sessionView.processDataLimitExceededStart', + { + defaultMessage: 'Data limit reached for', + } +); + +export const PROCESS_DATA_LIMIT_EXCEEDED_END = i18n.translate( + 'xpack.sessionView.processDataLimitExceededEnd', + { + defaultMessage: 'See "max_kilobytes_per_process" in advanced policy configuration.', + } +); + +export const VIEW_POLICIES = i18n.translate('xpack.sessionView.viewPoliciesLink', { + defaultMessage: 'VIEW POLICIES', +}); diff --git a/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts b/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts index 3c430d691e3f7..fee2aff4b5458 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts +++ b/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts @@ -9,7 +9,7 @@ * Copyright (c) 2017 The xterm.js authors. All rights reserved. * @license MIT */ -import { Terminal, IDisposable, ITerminalAddon, ISelectionPosition } from 'xterm'; +import { Terminal, IDisposable, ITerminalAddon, IBufferRange } from 'xterm'; export interface ISearchOptions { regex?: boolean; @@ -83,14 +83,14 @@ export class SearchAddon implements ITerminalAddon { let startCol = 0; let startRow = 0; - let currentSelection: ISelectionPosition | undefined; + let currentSelection: IBufferRange | undefined; if (this._terminal.hasSelection()) { const incremental = searchOptions ? searchOptions.incremental : false; // Start from the selection end if there is a selection // For incremental search, use existing row currentSelection = this._terminal.getSelectionPosition()!; - startRow = incremental ? currentSelection.startRow : currentSelection.endRow; - startCol = incremental ? currentSelection.startColumn : currentSelection.endColumn; + startRow = incremental ? currentSelection.start.y : currentSelection.end.y; + startCol = incremental ? currentSelection.start.x : currentSelection.end.x; } if (searchOptions?.lastLineOnly) { @@ -139,7 +139,7 @@ export class SearchAddon implements ITerminalAddon { // If there is only one result, wrap back and return selection if it exists. if (!result && currentSelection) { - searchPosition.startRow = currentSelection.startRow; + searchPosition.startRow = currentSelection.start.y; searchPosition.startCol = 0; result = this._findInLine(term, searchPosition, searchOptions); } @@ -170,12 +170,12 @@ export class SearchAddon implements ITerminalAddon { let startCol = this._terminal.cols; let result: ISearchResult | undefined; const incremental = searchOptions ? searchOptions.incremental : false; - let currentSelection: ISelectionPosition | undefined; + let currentSelection: IBufferRange | undefined; if (this._terminal.hasSelection()) { currentSelection = this._terminal.getSelectionPosition()!; // Start from selection start if there is a selection - startRow = currentSelection.startRow; - startCol = currentSelection.startColumn; + startRow = currentSelection.start.y; + startCol = currentSelection.start.x; } else if (searchOptions?.lastLineOnly) { startRow = this._terminal.buffer.active.cursorY - 1; startCol = this._terminal.cols; @@ -194,8 +194,8 @@ export class SearchAddon implements ITerminalAddon { if (!isOldResultHighlighted) { // If selection was not able to be expanded to the right, then try reverse search if (currentSelection) { - searchPosition.startRow = currentSelection.endRow; - searchPosition.startCol = currentSelection.endColumn; + searchPosition.startRow = currentSelection.end.y; + searchPosition.startCol = currentSelection.end.x; } result = this._findInLine(term, searchPosition, searchOptions, true); } diff --git a/x-pack/plugins/session_view/public/components/tty_player_controls/index.test.tsx b/x-pack/plugins/session_view/public/components/tty_player_controls/index.test.tsx index 8a536e1ae0228..61a3958c1b88d 100644 --- a/x-pack/plugins/session_view/public/components/tty_player_controls/index.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player_controls/index.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { AppContextTestRender, createAppRootMockRenderer } from '../../test'; import { ProcessEvent } from '../../../common/types/process_tree'; import { TTYPlayerControls, TTYPlayerControlsDeps } from '.'; +import { TTYPlayerLineMarkerType } from './tty_player_controls_markers'; const MOCK_PROCESS_EVENT_START: ProcessEvent = { process: { @@ -100,11 +101,11 @@ describe('TTYPlayerControls component', () => { expect(props.onSeekLine).toHaveBeenCalledWith(9); }); - it('render output markers', async () => { + it('render process_changed markers', async () => { renderResult = mockedContext.render(); expect( renderResult.queryAllByRole('button', { - name: 'output', + name: TTYPlayerLineMarkerType.ProcessChanged, }) ).toHaveLength(props.processStartMarkers.length); }); @@ -115,12 +116,10 @@ describe('TTYPlayerControls component', () => { event: { process: { ...MOCK_PROCESS_EVENT_MIDDLE, - io: { - max_bytes_per_process_exceeded: true, - }, }, }, line: 2, + maxBytesExceeded: true, }, { event: MOCK_PROCESS_EVENT_END, line: 4 }, ]; @@ -129,12 +128,12 @@ describe('TTYPlayerControls component', () => { ); expect( renderResult.queryAllByRole('button', { - name: 'output', + name: TTYPlayerLineMarkerType.ProcessChanged, }) ).toHaveLength(2); expect( renderResult.queryAllByRole('button', { - name: 'data_limited', + name: TTYPlayerLineMarkerType.ProcessDataLimitReached, }) ).toHaveLength(1); }); diff --git a/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/index.tsx b/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/index.tsx index b10ba00e1fc2a..e84ed7fcf34a9 100644 --- a/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/index.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/index.tsx @@ -19,9 +19,14 @@ type Props = { onSeekLine(line: number): void; }; +export enum TTYPlayerLineMarkerType { + ProcessChanged = 'process_changed', + ProcessDataLimitReached = 'data_limited', +} + type TTYPlayerLineMarker = { line: number; - type: 'output' | 'data_limited'; + type: TTYPlayerLineMarkerType; name: string; }; @@ -44,10 +49,11 @@ export const TTYPlayerControlsMarkers = ({ return []; } return processStartMarkers.map( - ({ event, line }) => + ({ event, line, maxBytesExceeded }) => ({ - type: - event.process?.io?.max_bytes_per_process_exceeded === true ? 'data_limited' : 'output', + type: maxBytesExceeded + ? TTYPlayerLineMarkerType.ProcessDataLimitReached + : TTYPlayerLineMarkerType.ProcessChanged, line, name: event.process?.name, } as TTYPlayerLineMarker) diff --git a/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/styles.ts b/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/styles.ts index f48cfd3795eb0..48c7c67128c64 100644 --- a/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/styles.ts +++ b/x-pack/plugins/session_view/public/components/tty_player_controls/tty_player_controls_markers/styles.ts @@ -9,7 +9,7 @@ import { useMemo } from 'react'; import { CSSObject } from '@emotion/react'; import { useEuiTheme } from '../../../hooks'; -type TTYPlayerLineMarkerType = 'output' | 'data_limited'; +import { TTYPlayerLineMarkerType } from '.'; export const useStyles = (progress: number) => { const { euiTheme, euiVars } = useEuiTheme(); @@ -30,7 +30,7 @@ export const useStyles = (progress: number) => { }; const getMarkerBackgroundColor = (type: TTYPlayerLineMarkerType, selected: boolean) => { - if (type === 'data_limited') { + if (type === TTYPlayerLineMarkerType.ProcessDataLimitReached) { return euiVars.terminalOutputMarkerWarning; } if (selected) { @@ -105,7 +105,7 @@ export const useStyles = (progress: number) => { left: progress + '%', top: 16, fill: - type === 'data_limited' + type === TTYPlayerLineMarkerType.ProcessDataLimitReached ? euiVars.terminalOutputMarkerWarning : euiVars.terminalOutputMarkerAccent, }); diff --git a/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx b/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx index 06fa17a6c151c..7b8adbc47d52d 100644 --- a/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx @@ -7,7 +7,6 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import userEvent from '@testing-library/user-event'; -import { fireEvent } from '@testing-library/dom'; import { AppContextTestRender, createAppRootMockRenderer } from '../../test'; import { sessionViewIOEventsMock } from '../../../common/mocks/responses/session_view_io_events.mock'; import { useIOLines } from '../tty_player/hooks'; @@ -35,6 +34,8 @@ describe('TTYSearchBar component', () => { seekToLine: jest.fn(), xTermSearchFn: jest.fn(), setIsPlaying: jest.fn(), + searchQuery: '', + setSearchQuery: jest.fn(), }; }); @@ -44,33 +45,20 @@ describe('TTYSearchBar component', () => { }); it('does a search when a user enters text and hits enter', async () => { - renderResult = mockedContext.render(); - - const searchInput = renderResult.queryByTestId('sessionView:searchBar')?.querySelector('input'); - if (searchInput) { - userEvent.type(searchInput, '-h'); - fireEvent.keyUp(searchInput, { key: 'Enter', code: 'Enter' }); - } + renderResult = mockedContext.render(); expect(props.seekToLine).toHaveBeenCalledTimes(1); // there is a slight delay in the seek in xtermjs, so we wait 100ms before trying to highlight a result. await new Promise((r) => setTimeout(r, 100)); - expect(props.xTermSearchFn).toHaveBeenCalledTimes(2); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '', 0); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 6); + expect(props.xTermSearchFn).toHaveBeenCalledTimes(1); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '-h', 6); expect(props.setIsPlaying).toHaveBeenCalledWith(false); }); it('calls seekToline and xTermSearchFn when currentMatch changes', async () => { - renderResult = mockedContext.render(); - - const searchInput = renderResult.queryByTestId('sessionView:searchBar')?.querySelector('input'); - if (searchInput) { - userEvent.type(searchInput, '-h'); - fireEvent.keyUp(searchInput, { key: 'Enter', code: 'Enter' }); - } + renderResult = mockedContext.render(); await new Promise((r) => setTimeout(r, 100)); @@ -83,27 +71,23 @@ describe('TTYSearchBar component', () => { expect(props.seekToLine).toHaveBeenNthCalledWith(1, 26); expect(props.seekToLine).toHaveBeenNthCalledWith(2, 100); - expect(props.xTermSearchFn).toHaveBeenCalledTimes(3); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '', 0); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 6); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(3, '-h', 13); - expect(props.setIsPlaying).toHaveBeenCalledTimes(3); + expect(props.xTermSearchFn).toHaveBeenCalledTimes(2); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '-h', 6); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 13); + expect(props.setIsPlaying).toHaveBeenCalledTimes(2); }); it('calls xTermSearchFn with empty query when search is cleared', async () => { - renderResult = mockedContext.render(); - - const searchInput = renderResult.queryByTestId('sessionView:searchBar')?.querySelector('input'); - if (searchInput) { - userEvent.type(searchInput, '-h'); - fireEvent.keyUp(searchInput, { key: 'Enter', code: 'Enter' }); - } + renderResult = mockedContext.render(); await new Promise((r) => setTimeout(r, 100)); userEvent.click(renderResult.getByTestId('clearSearchButton')); await new Promise((r) => setTimeout(r, 100)); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(3, '', 0); + renderResult.rerender(); + + expect(props.setSearchQuery).toHaveBeenNthCalledWith(1, ''); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '', 0); expect(props.setIsPlaying).toHaveBeenCalledWith(false); }); }); diff --git a/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx b/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx index 18b829127ab2d..47d166167bb2a 100644 --- a/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx +++ b/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx @@ -20,6 +20,8 @@ export interface TTYSearchBarDeps { seekToLine(index: number): void; xTermSearchFn(query: string, index: number): void; setIsPlaying(value: boolean): void; + searchQuery: string; + setSearchQuery(value: string): void; } const STRIP_NEWLINES_REGEX = /^(\r\n|\r|\n|\n\r)/; @@ -29,9 +31,10 @@ export const TTYSearchBar = ({ seekToLine, xTermSearchFn, setIsPlaying, + searchQuery, + setSearchQuery, }: TTYSearchBarDeps) => { const [currentMatch, setCurrentMatch] = useState(null); - const [searchQuery, setSearchQuery] = useState(''); const jumpToMatch = useCallback( (match) => { @@ -105,7 +108,7 @@ export const TTYSearchBar = ({ setSearchQuery(query); setCurrentMatch(null); }, - [setIsPlaying] + [setIsPlaying, setSearchQuery] ); const onSetCurrentMatch = useCallback( diff --git a/x-pack/plugins/session_view/public/test/index.tsx b/x-pack/plugins/session_view/public/test/index.tsx index 244560d366ac4..6ccc8ca2b1991 100644 --- a/x-pack/plugins/session_view/public/test/index.tsx +++ b/x-pack/plugins/session_view/public/test/index.tsx @@ -17,6 +17,7 @@ import { CoreStart } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { SECURITY_APP_ID, SESSION_VIEW_APP_ID } from '../../common/constants'; type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult; @@ -46,8 +47,10 @@ const createCoreStartMock = ( // Mock the certain APP Ids returned by `application.getUrlForApp()` coreStart.application.getUrlForApp.mockImplementation((appId) => { switch (appId) { - case 'sessionView': + case SESSION_VIEW_APP_ID: return '/app/sessionView'; + case SECURITY_APP_ID: + return '/app/security'; default: return `${appId} not mocked!`; } diff --git a/x-pack/plugins/session_view/public/types.ts b/x-pack/plugins/session_view/public/types.ts index d276f0e9518a9..fa5f9d1ebb04d 100644 --- a/x-pack/plugins/session_view/public/types.ts +++ b/x-pack/plugins/session_view/public/types.ts @@ -27,6 +27,7 @@ export interface SessionViewDeps { // Callback used when alert flyout panel is closed handleOnAlertDetailsClosed: () => void ) => void; + canAccessEndpointManagement?: boolean; } export interface EuiTabProps { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts index 2b13553d4e604..ea71e64f2258a 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts @@ -58,7 +58,7 @@ describe('', () => { /** * TODO: investigate why we need to skip this test. * My guess is a change in the useRequest() hook and maybe a setTimout() that hasn't been - * mocked with jest.useFakeTimers(); + * mocked with jest.useFakeTimers('legacy'); * I tested locally and the loading spinner is present in the UI so skipping this test for now. */ test.skip('should display a loading while fetching the repositories', () => { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts index 3a34926272e07..c9da67b98d622 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts @@ -37,7 +37,7 @@ describe('', () => { /** * TODO: investigate why we need to skip this test. * My guess is a change in the useRequest() hook and maybe a setTimout() that hasn't been - * mocked with jest.useFakeTimers(); + * mocked with jest.useFakeTimers('legacy'); * I tested locally and the loading spinner is present in the UI so skipping this test for now. */ test.skip('should indicate that the repository types are loading', () => { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/snapshot_list.test.tsx b/x-pack/plugins/snapshot_restore/__jest__/client_integration/snapshot_list.test.tsx index bc6eae3fcd573..a94d0fdcd371d 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/snapshot_list.test.tsx +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/snapshot_list.test.tsx @@ -55,7 +55,7 @@ describe('', () => { let getSearchErrorText: SnapshotListTestBed['actions']['getSearchErrorText']; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const snapshot = fixtures.getSnapshot({ repository: REPOSITORY_NAME, snapshot: getRandomString(), diff --git a/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts b/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts index 5aaeb97ae76c4..8250a993192bb 100644 --- a/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts +++ b/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts @@ -214,7 +214,7 @@ test('maintains unavailable status if default space cannot be created', async () }); test('retries operation', async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const { repository, serviceStatus$ } = setup({ elasticsearchStatus: ServiceStatusLevels.available, diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.test.tsx index 643d6c79afc7d..e6e1b18c5de8a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.test.tsx @@ -81,7 +81,7 @@ describe('ThresholdVisualization', () => { test('periodically requests visualization data', async () => { const refreshRate = 10; - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); const wrapper = mountWithIntl( ( - - - - - + + + + + + + + + + ); diff --git a/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts b/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts index 5aa7ee96f25b1..648337218979c 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts @@ -48,10 +48,10 @@ journey('DataViewPermissions', async ({ page, params }) => { step('Click explore data button', async () => { await page.click(byTestId('uptimeExploreDataButton')); await waitForLoadingToFinish({ page }); - await page.waitForSelector(`text=${permissionError}`, TIMEOUT_60_SEC); - expect(await page.$(`text=${permissionError}`)).toBeTruthy(); }); -}); -const permissionError = - "Unable to create Data View. You don't have the required permission, please contact your admin."; + step('it renders for viewer user as well', async () => { + await page.waitForSelector(`text=browser`, TIMEOUT_60_SEC); + expect(await page.$(`text=Monitor duration`)).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_container.test.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_container.test.tsx index 3580df2c317a7..6d8b0b455a5f2 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_container.test.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_container.test.tsx @@ -135,7 +135,7 @@ const defaultState = { describe('WaterfallChartContainer', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); it('does not display waterfall chart unavailable when isWaterfallSupported is true', () => { diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx index 81ed2d024340c..ba26366644dbd 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx @@ -26,7 +26,7 @@ const getHighLightedItems = (query: string, filters: string[]) => { describe('WaterfallChartWrapper', () => { beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); it('renders the correct sidebar items', () => { diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_filter.test.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_filter.test.tsx index 42cb46427011c..c36e46b9d999b 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_filter.test.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/synthetics/step_detail/waterfall/waterfall_filter.test.tsx @@ -19,7 +19,7 @@ import { } from '../../waterfall/components/translations'; describe('waterfall filter', () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); it('renders correctly', () => { const { getByLabelText, getByTitle } = render( diff --git a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts new file mode 100644 index 0000000000000..ac71653c31c8f --- /dev/null +++ b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import uuid from 'uuid'; +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { bulkRemoveIfExist } from './bulk_remove_if_exist'; +import { taskStoreMock } from '../task_store.mock'; + +describe('removeIfExists', () => { + const ids = [uuid.v4(), uuid.v4()]; + + test('removes the tasks by its IDs', async () => { + const ts = taskStoreMock.create({}); + + expect(await bulkRemoveIfExist(ts, ids)).toBe(undefined); + expect(ts.bulkRemove).toHaveBeenCalledWith(ids); + }); + + test('handles 404 errors caused by the task not existing', async () => { + const ts = taskStoreMock.create({}); + + ts.bulkRemove.mockRejectedValue( + SavedObjectsErrorHelpers.createGenericNotFoundError('task', ids[0]) + ); + + expect(await bulkRemoveIfExist(ts, ids)).toBe(undefined); + expect(ts.bulkRemove).toHaveBeenCalledWith(ids); + }); + + test('throws if any other error is caused by task removal', async () => { + const ts = taskStoreMock.create({}); + + const error = SavedObjectsErrorHelpers.createInvalidVersionError(uuid.v4()); + ts.bulkRemove.mockRejectedValue(error); + + expect(bulkRemoveIfExist(ts, ids)).rejects.toBe(error); + expect(ts.bulkRemove).toHaveBeenCalledWith(ids); + }); +}); diff --git a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts new file mode 100644 index 0000000000000..c3c1a61868e60 --- /dev/null +++ b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { TaskStore } from '../task_store'; + +/** + * Removes a task from the store, ignoring a not found error + * Other errors are re-thrown + * + * @param taskStore + * @param taskIds + */ +export async function bulkRemoveIfExist(taskStore: TaskStore, taskIds: string[]) { + try { + return await taskStore.bulkRemove(taskIds); + } catch (err) { + if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { + throw err; + } + } +} diff --git a/x-pack/plugins/task_manager/server/mocks.ts b/x-pack/plugins/task_manager/server/mocks.ts index 6cf405c4a1b28..97ebb227d17c0 100644 --- a/x-pack/plugins/task_manager/server/mocks.ts +++ b/x-pack/plugins/task_manager/server/mocks.ts @@ -27,6 +27,7 @@ const createStartMock = () => { ephemeralRunNow: jest.fn(), ensureScheduled: jest.fn(), removeIfExists: jest.fn(), + bulkRemoveIfExist: jest.fn(), supportsEphemeralTasks: jest.fn(), bulkUpdateSchedules: jest.fn(), bulkSchedule: jest.fn(), diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index e4cf8730f6dbc..d16fab4a48e20 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -18,10 +18,12 @@ import { ServiceStatusLevels, CoreStatus, } from '@kbn/core/server'; +import type { SavedObjectsBulkDeleteResponse } from '@kbn/core/server'; import { TaskPollingLifecycle } from './polling_lifecycle'; import { TaskManagerConfig } from './config'; import { createInitialMiddleware, addMiddlewareToChain, Middleware } from './lib/middleware'; import { removeIfExists } from './lib/remove_if_exists'; +import { bulkRemoveIfExist } from './lib/bulk_remove_if_exist'; import { setupSavedObjects } from './saved_objects'; import { TaskDefinitionRegistry, TaskTypeDictionary, REMOVED_TYPES } from './task_type_dictionary'; import { AggregationOpts, FetchResult, SearchOpts, TaskStore } from './task_store'; @@ -33,6 +35,7 @@ import { EphemeralTaskLifecycle } from './ephemeral_task_lifecycle'; import { EphemeralTask, ConcreteTaskInstance } from './task'; import { registerTaskManagerUsageCollector } from './usage'; import { TASK_MANAGER_INDEX } from './constants'; + export interface TaskManagerSetupContract { /** * @deprecated @@ -59,7 +62,11 @@ export type TaskManagerStartContract = Pick< > & Pick & { removeIfExists: TaskStore['remove']; - } & { supportsEphemeralTasks: () => boolean }; + } & { + bulkRemoveIfExist: (ids: string[]) => Promise; + } & { + supportsEphemeralTasks: () => boolean; + }; export class TaskManagerPlugin implements Plugin @@ -248,6 +255,7 @@ export class TaskManagerPlugin taskStore.aggregate(opts), get: (id: string) => taskStore.get(id), remove: (id: string) => taskStore.remove(id), + bulkRemoveIfExist: (ids: string[]) => bulkRemoveIfExist(taskStore, ids), removeIfExists: (id: string) => removeIfExists(taskStore, id), schedule: (...args) => taskScheduling.schedule(...args), bulkSchedule: (...args) => taskScheduling.bulkSchedule(...args), diff --git a/x-pack/plugins/task_manager/server/polling/delay_on_claim_conflicts.test.ts b/x-pack/plugins/task_manager/server/polling/delay_on_claim_conflicts.test.ts index cdfebd1156c55..c57c1b2b7bbc3 100644 --- a/x-pack/plugins/task_manager/server/polling/delay_on_claim_conflicts.test.ts +++ b/x-pack/plugins/task_manager/server/polling/delay_on_claim_conflicts.test.ts @@ -16,7 +16,7 @@ import { TaskLifecycleEvent } from '../polling_lifecycle'; import { FillPoolResult } from '../lib/fill_pool'; describe('delayOnClaimConflicts', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); test( 'initializes with a delay of 0', diff --git a/x-pack/plugins/task_manager/server/polling/task_poller.test.ts b/x-pack/plugins/task_manager/server/polling/task_poller.test.ts index f01ea2f018cb9..396cef0cfa7a6 100644 --- a/x-pack/plugins/task_manager/server/polling/task_poller.test.ts +++ b/x-pack/plugins/task_manager/server/polling/task_poller.test.ts @@ -14,7 +14,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { asOk, asErr } from '../lib/result_type'; describe('TaskPoller', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('legacy')); test( 'intializes the poller with the provided interval', diff --git a/x-pack/plugins/task_manager/server/task_store.mock.ts b/x-pack/plugins/task_manager/server/task_store.mock.ts index 4e9c5dda39527..cc9aac708b2de 100644 --- a/x-pack/plugins/task_manager/server/task_store.mock.ts +++ b/x-pack/plugins/task_manager/server/task_store.mock.ts @@ -20,6 +20,7 @@ export const taskStoreMock = { schedule: jest.fn(), bulkSchedule: jest.fn(), bulkUpdate: jest.fn(), + bulkRemove: jest.fn(), get: jest.fn(), getLifecycle: jest.fn(), fetch: jest.fn(), diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 561d4ac6a0989..7bc731a0d8b6b 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -25,6 +25,8 @@ import { mockLogger } from './test_utils'; const savedObjectsClient = savedObjectsRepositoryMock.create(); const serializer = savedObjectsServiceMock.createSerializer(); +const randomId = () => `id-${_.random(1, 20)}`; + beforeEach(() => jest.resetAllMocks()); const mockedDate = new Date('2019-02-12T21:01:22.479Z'); @@ -529,6 +531,41 @@ describe('TaskStore', () => { }); }); + describe('bulkRemove', () => { + let store: TaskStore; + + const tasksIdsToDelete = [randomId(), randomId()]; + + beforeAll(() => { + store = new TaskStore({ + index: 'tasky', + taskManagerId: '', + serializer, + esClient: elasticsearchServiceMock.createClusterClient().asInternalUser, + definitions: taskDefinitions, + savedObjectsRepository: savedObjectsClient, + }); + }); + + test('removes the tasks with the specified ids', async () => { + const result = await store.bulkRemove(tasksIdsToDelete); + expect(result).toBeUndefined(); + expect(savedObjectsClient.bulkDelete).toHaveBeenCalledWith([ + { type: 'task', id: tasksIdsToDelete[0] }, + { type: 'task', id: tasksIdsToDelete[1] }, + ]); + }); + + test('pushes error from saved objects client to errors$', async () => { + const firstErrorPromise = store.errors$.pipe(first()).toPromise(); + savedObjectsClient.bulkDelete.mockRejectedValue(new Error('Failure')); + await expect(store.bulkRemove(tasksIdsToDelete)).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failure"` + ); + expect(await firstErrorPromise).toMatchInlineSnapshot(`[Error: Failure]`); + }); + }); + describe('get', () => { let store: TaskStore; @@ -802,5 +839,3 @@ describe('TaskStore', () => { }); }); }); - -const randomId = () => `id-${_.random(1, 20)}`; diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 5d1a7246440f4..c2c003ff6f7bb 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -12,6 +12,7 @@ import { Subject } from 'rxjs'; import { omit, defaults } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SavedObjectsBulkDeleteResponse } from '@kbn/core/server'; import { SavedObject, @@ -294,6 +295,22 @@ export class TaskStore { } } + /** + * Bulk removes the specified tasks from the index. + * + * @param {SavedObjectsBulkDeleteObject[]} savedObjectsToDelete + * @returns {Promise} + */ + public async bulkRemove(taskIds: string[]): Promise { + try { + const savedObjectsToDelete = taskIds.map((taskId) => ({ id: taskId, type: 'task' })); + return await this.savedObjectsRepository.bulkDelete(savedObjectsToDelete); + } catch (e) { + this.errors$.next(e); + throw e; + } + } + /** * Gets a task by id * diff --git a/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts b/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts index 17c4d79e60dcc..4de89a37f8833 100644 --- a/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts +++ b/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts @@ -53,6 +53,15 @@ describe('Indicators', () => { esArchiverUnload('threat_intelligence'); }); + describe('Indicators page loading', () => { + it('verify the fleet plugin integrations endpoint exists', () => { + cy.request({ + method: 'GET', + url: '/api/fleet/epm/packages', + }).should((response) => expect(response.status).to.eq(200)); + }); + }); + describe('Indicators page basics', () => { before(() => { cy.visit(THREAT_INTELLIGENCE); diff --git a/x-pack/plugins/threat_intelligence/cypress/e2e/query_bar.cy.ts b/x-pack/plugins/threat_intelligence/cypress/e2e/query_bar.cy.ts index e2a0459dc3fd6..4c55a0505d34c 100644 --- a/x-pack/plugins/threat_intelligence/cypress/e2e/query_bar.cy.ts +++ b/x-pack/plugins/threat_intelligence/cypress/e2e/query_bar.cy.ts @@ -6,23 +6,23 @@ */ import { - INDICATOR_TYPE_CELL, - TOGGLE_FLYOUT_BUTTON, - FLYOUT_CLOSE_BUTTON, - KQL_FILTER, - INDICATORS_TABLE_CELL_FILTER_IN_BUTTON, - INDICATORS_TABLE_CELL_FILTER_OUT_BUTTON, - FLYOUT_TABLE_TAB_ROW_FILTER_IN_BUTTON, - FLYOUT_TABLE_TAB_ROW_FILTER_OUT_BUTTON, - BARCHART_POPOVER_BUTTON, BARCHART_FILTER_IN_BUTTON, BARCHART_FILTER_OUT_BUTTON, + BARCHART_POPOVER_BUTTON, + FLYOUT_CLOSE_BUTTON, FLYOUT_OVERVIEW_TAB_BLOCKS_FILTER_IN_BUTTON, FLYOUT_OVERVIEW_TAB_BLOCKS_FILTER_OUT_BUTTON, + FLYOUT_OVERVIEW_TAB_BLOCKS_ITEM, FLYOUT_OVERVIEW_TAB_TABLE_ROW_FILTER_IN_BUTTON, FLYOUT_OVERVIEW_TAB_TABLE_ROW_FILTER_OUT_BUTTON, - FLYOUT_OVERVIEW_TAB_BLOCKS_ITEM, + FLYOUT_TABLE_TAB_ROW_FILTER_IN_BUTTON, + FLYOUT_TABLE_TAB_ROW_FILTER_OUT_BUTTON, FLYOUT_TABS, + INDICATOR_TYPE_CELL, + INDICATORS_TABLE_CELL_FILTER_IN_BUTTON, + INDICATORS_TABLE_CELL_FILTER_OUT_BUTTON, + KQL_FILTER, + TOGGLE_FLYOUT_BUTTON, } from '../screens/indicators'; import { selectRange } from '../tasks/select_range'; import { login } from '../tasks/login'; diff --git a/x-pack/plugins/threat_intelligence/cypress/e2e/timeline.cy.ts b/x-pack/plugins/threat_intelligence/cypress/e2e/timeline.cy.ts index de3d0adf72c81..eb24ecaaa5a5f 100644 --- a/x-pack/plugins/threat_intelligence/cypress/e2e/timeline.cy.ts +++ b/x-pack/plugins/threat_intelligence/cypress/e2e/timeline.cy.ts @@ -9,18 +9,18 @@ import { BARCHART_POPOVER_BUTTON, BARCHART_TIMELINE_BUTTON, FLYOUT_CLOSE_BUTTON, + FLYOUT_OVERVIEW_TAB_BLOCKS_ITEM, + FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON, FLYOUT_OVERVIEW_TAB_TABLE_ROW_TIMELINE_BUTTON, FLYOUT_TABLE_TAB_ROW_TIMELINE_BUTTON, FLYOUT_TABS, + INDICATOR_FLYOUT_INVESTIGATE_IN_TIMELINE_BUTTON, INDICATOR_TYPE_CELL, INDICATORS_TABLE_CELL_TIMELINE_BUTTON, + INDICATORS_TABLE_INVESTIGATE_IN_TIMELINE_BUTTON_ICON, TIMELINE_DRAGGABLE_ITEM, TOGGLE_FLYOUT_BUTTON, UNTITLED_TIMELINE_BUTTON, - FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON, - FLYOUT_OVERVIEW_TAB_BLOCKS_ITEM, - INDICATORS_TABLE_INVESTIGATE_IN_TIMELINE_BUTTON_ICON, - INDICATOR_FLYOUT_INVESTIGATE_IN_TIMELINE_BUTTON, } from '../screens/indicators'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { login } from '../tasks/login'; diff --git a/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts b/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts index f33034dccb9c5..accbed00a47e9 100644 --- a/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts +++ b/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts @@ -5,8 +5,8 @@ * 2.0. */ -import Url from 'url'; import type { UrlObject } from 'url'; +import Url from 'url'; import * as yaml from 'js-yaml'; diff --git a/x-pack/plugins/threat_intelligence/public/containers/enterprise_guard/enterprise_guard.tsx b/x-pack/plugins/threat_intelligence/public/containers/enterprise_guard/enterprise_guard.tsx index 370c28e8d50f9..e87edb2a35162 100644 --- a/x-pack/plugins/threat_intelligence/public/containers/enterprise_guard/enterprise_guard.tsx +++ b/x-pack/plugins/threat_intelligence/public/containers/enterprise_guard/enterprise_guard.tsx @@ -7,7 +7,8 @@ import React, { FC } from 'react'; import { Paywall } from '../../components/paywall'; -import { useKibana, useSecurityContext } from '../../hooks'; +import { useKibana } from '../../hooks/use_kibana'; +import { useSecurityContext } from '../../hooks/use_security_context'; import { SecuritySolutionPluginTemplateWrapper } from '../security_solution_plugin_template_wrapper'; export const EnterpriseGuard: FC = ({ children }) => { diff --git a/x-pack/plugins/threat_intelligence/public/containers/indicators_page_wrapper.tsx b/x-pack/plugins/threat_intelligence/public/containers/indicators_page_wrapper.tsx new file mode 100644 index 0000000000000..f5fe0d496ace3 --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/containers/indicators_page_wrapper.tsx @@ -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 React, { Suspense, VFC } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { IndicatorsPage } from '../modules/indicators/pages'; +import { SecuritySolutionPluginTemplateWrapper } from './security_solution_plugin_template_wrapper'; + +export const IndicatorsPageWrapper: VFC = () => { + const queryClient = new QueryClient(); + + return ( + + + }> + + + + + ); +}; + +// Note: This is for lazy loading +// eslint-disable-next-line import/no-default-export +export default IndicatorsPageWrapper; diff --git a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/__snapshots__/integrations_guard.test.tsx.snap b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/__snapshots__/integrations_guard.test.tsx.snap index 95785cffd6ad3..1fcca470c6f15 100644 --- a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/__snapshots__/integrations_guard.test.tsx.snap +++ b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/__snapshots__/integrations_guard.test.tsx.snap @@ -1,24 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`checking if the page should be visible (based on indicator count) when indicator count is being loaded should render nothing at all: loading 1`] = ` - - -`; - -exports[`checking if the page should be visible (based on indicator count) when indicator count is loaded and there are no indicators should render empty page when no indicators are found: no indicators 1`] = ` +exports[`IntegrationsGuard should render empty page when no indicators are found and no ti integrations are installed 1`] = `
`; -exports[`checking if the page should be visible (based on indicator count) when loading is done and we have some indicators should render indicators table: indicators are present 1`] = ` +exports[`IntegrationsGuard should render indicators page when we have some ti integrations installed 1`] = ` should be restricted `; + +exports[`IntegrationsGuard should render indicators table when we have some indicators 1`] = ` + + should be restricted + +`; + +exports[`IntegrationsGuard should render loading when indicator count and integrations are being loaded 1`] = ` + + +`; + +exports[`IntegrationsGuard should render loading when indicator only is loading 1`] = ` + + +`; + +exports[`IntegrationsGuard should render loading when integrations only are loading 1`] = ` + + +`; diff --git a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.test.tsx b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.test.tsx index ce8b3b9aaaa98..b0976721311fc 100644 --- a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.test.tsx +++ b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.test.tsx @@ -5,76 +5,164 @@ * 2.0. */ +import { UseQueryResult } from '@tanstack/react-query'; import { render } from '@testing-library/react'; import React from 'react'; import { IntegrationsGuard } from '.'; import { TestProvidersComponent } from '../../common/mocks/test_providers'; -import { useIntegrationsPageLink, useTIDocumentationLink } from '../../hooks'; +import { + Integration, + useIntegrations, + useIntegrationsPageLink, + useTIDocumentationLink, +} from '../../hooks'; import { useIndicatorsTotalCount } from '../../modules/indicators'; +import { INSTALLATION_STATUS, THREAT_INTELLIGENCE_CATEGORY } from '../../utils'; jest.mock('../../modules/indicators/hooks/use_total_count'); jest.mock('../../hooks/use_integrations_page_link'); jest.mock('../../hooks/use_documentation_link'); +jest.mock('../../hooks/use_integrations'); -describe('checking if the page should be visible (based on indicator count)', () => { - describe('when indicator count is being loaded', () => { - it('should render nothing at all', () => { - ( - useIndicatorsTotalCount as jest.MockedFunction - ).mockReturnValue({ - count: 0, - isLoading: true, - }); - ( - useIntegrationsPageLink as jest.MockedFunction - ).mockReturnValue(''); - ( - useTIDocumentationLink as jest.MockedFunction - ).mockReturnValue(''); - - const { asFragment } = render(should be restricted, { - wrapper: TestProvidersComponent, - }); - - expect(asFragment()).toMatchSnapshot('loading'); +describe('IntegrationsGuard', () => { + it('should render loading when indicator count and integrations are being loaded', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 0, + isLoading: true, }); + ( + useIntegrationsPageLink as jest.MockedFunction + ).mockReturnValue(''); + (useTIDocumentationLink as jest.MockedFunction).mockReturnValue( + '' + ); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: true, + data: [], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, + }); + + expect(asFragment()).toMatchSnapshot(); + }); + + it('should render loading when indicator only is loading', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 0, + isLoading: true, + }); + ( + useIntegrationsPageLink as jest.MockedFunction + ).mockReturnValue(''); + (useTIDocumentationLink as jest.MockedFunction).mockReturnValue( + '' + ); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: false, + data: [], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, + }); + + expect(asFragment()).toMatchSnapshot(); + }); + + it('should render loading when integrations only are loading', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 0, + isLoading: true, + }); + ( + useIntegrationsPageLink as jest.MockedFunction + ).mockReturnValue(''); + (useTIDocumentationLink as jest.MockedFunction).mockReturnValue( + '' + ); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: true, + data: [], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, + }); + + expect(asFragment()).toMatchSnapshot(); + }); + + it('should render empty page when no indicators are found and no ti integrations are installed', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 0, + isLoading: false, + }); + ( + useIntegrationsPageLink as jest.MockedFunction + ).mockReturnValue(''); + (useTIDocumentationLink as jest.MockedFunction).mockReturnValue( + '' + ); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: false, + data: [], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, + }); + expect(asFragment()).toMatchSnapshot(); }); - describe('when indicator count is loaded and there are no indicators', () => { - it('should render empty page when no indicators are found', async () => { - ( - useIndicatorsTotalCount as jest.MockedFunction - ).mockReturnValue({ - count: 0, - isLoading: false, - }); - ( - useIntegrationsPageLink as jest.MockedFunction - ).mockReturnValue(''); - ( - useTIDocumentationLink as jest.MockedFunction - ).mockReturnValue(''); - - const { asFragment } = render(should be restricted, { - wrapper: TestProvidersComponent, - }); - expect(asFragment()).toMatchSnapshot('no indicators'); + it('should render indicators table when we have some indicators', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 7, + isLoading: false, + }); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: false, + data: [], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, }); + expect(asFragment()).toMatchSnapshot(); }); - describe('when loading is done and we have some indicators', () => { - it('should render indicators table', async () => { - ( - useIndicatorsTotalCount as jest.MockedFunction - ).mockReturnValue({ - count: 7, - isLoading: false, - }); - - const { asFragment } = render(should be restricted, { - wrapper: TestProvidersComponent, - }); - expect(asFragment()).toMatchSnapshot('indicators are present'); + it('should render indicators page when we have some ti integrations installed', async () => { + ( + useIndicatorsTotalCount as jest.MockedFunction + ).mockReturnValue({ + count: 0, + isLoading: false, + }); + (useIntegrations as jest.MockedFunction).mockReturnValue({ + isLoading: false, + data: [ + { + categories: [THREAT_INTELLIGENCE_CATEGORY], + id: '123', + status: INSTALLATION_STATUS.Installed, + }, + ], + } as unknown as UseQueryResult); + + const { asFragment } = render(should be restricted, { + wrapper: TestProvidersComponent, }); + expect(asFragment()).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.tsx b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.tsx index eb639d6c50f75..4c225e283b919 100644 --- a/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.tsx +++ b/x-pack/plugins/threat_intelligence/public/containers/integrations_guard/integrations_guard.tsx @@ -7,18 +7,24 @@ import { EuiLoadingLogo } from '@elastic/eui'; import React, { FC } from 'react'; +import { useIntegrations } from '../../hooks'; import { EmptyPage } from '../../modules/empty_page'; import { useIndicatorsTotalCount } from '../../modules/indicators'; import { SecuritySolutionPluginTemplateWrapper } from '../security_solution_plugin_template_wrapper'; /** - * Renders children only if TI integrations are enabled + * Renders the indicators page if the user has some Threat Intelligence integrations installed or + * the user is receiving indicators. + * If none are received, show the EmptyPage with a link to go install integrations. + * While the indicators call and the integrations call are loading, display a loading screen. */ export const IntegrationsGuard: FC = ({ children }) => { - const { count: indicatorsTotalCount, isLoading: isIndicatorsTotalCountLoading } = + const { isLoading: indicatorsTotalCountLoading, count: indicatorsTotalCount } = useIndicatorsTotalCount(); - if (isIndicatorsTotalCountLoading) { + const { isLoading: integrationLoading, data: installedTIIntegrations } = useIntegrations(); + + if (integrationLoading || indicatorsTotalCountLoading) { return ( @@ -26,7 +32,7 @@ export const IntegrationsGuard: FC = ({ children }) => { ); } - const showEmptyPage = indicatorsTotalCount === 0; - - return showEmptyPage ? : <>{children}; + // show indicators page if there are indicators, or if some ti integrations have been added + const showIndicatorsPage = indicatorsTotalCount > 0 || (installedTIIntegrations || []).length > 0; + return showIndicatorsPage ? <>{children} : ; }; diff --git a/x-pack/plugins/threat_intelligence/public/containers/security_solution_plugin_template_wrapper.tsx b/x-pack/plugins/threat_intelligence/public/containers/security_solution_plugin_template_wrapper.tsx index e2e1a735b0c71..c4b97d1b7e722 100644 --- a/x-pack/plugins/threat_intelligence/public/containers/security_solution_plugin_template_wrapper.tsx +++ b/x-pack/plugins/threat_intelligence/public/containers/security_solution_plugin_template_wrapper.tsx @@ -8,7 +8,7 @@ import type { FC } from 'react'; import React from 'react'; import type { KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template-types'; -import { useKibana } from '../hooks'; +import { useKibana } from '../hooks/use_kibana'; /** * Uses securityLayout service to retrieve shared plugin wrapper component and renders plugin routes / children inside of it. diff --git a/x-pack/plugins/threat_intelligence/public/hooks/index.ts b/x-pack/plugins/threat_intelligence/public/hooks/index.ts index 369a364e99ac9..29c019274e946 100644 --- a/x-pack/plugins/threat_intelligence/public/hooks/index.ts +++ b/x-pack/plugins/threat_intelligence/public/hooks/index.ts @@ -8,6 +8,7 @@ export * from './use_documentation_link'; export * from './use_field_types'; export * from './use_inspector'; +export * from './use_integrations'; export * from './use_integrations_page_link'; export * from './use_kibana'; export * from './use_security_context'; diff --git a/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.test.tsx b/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.test.tsx new file mode 100644 index 0000000000000..ee868cc9803d6 --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.test.tsx @@ -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 React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query'; +import { INSTALLATION_STATUS, THREAT_INTELLIGENCE_CATEGORY } from '../utils'; + +const createWrapper = () => { + const queryClient = new QueryClient(); + return ({ children }: { children: any }) => ( + {children} + ); +}; + +const renderUseQuery = (result: { items: any[] }) => + renderHook(() => useQuery(['integrations'], () => result), { + wrapper: createWrapper(), + }); + +describe('useIntegrations', () => { + it('should have undefined data during loading state', async () => { + const mockIntegrations = { items: [] }; + const { result, waitFor } = renderUseQuery(mockIntegrations); + + await waitFor(() => result.current.isLoading); + + expect(result.current.isLoading).toBeTruthy(); + expect(result.current.data).toBeUndefined(); + }); + + it('should return integrations on success', async () => { + const mockIntegrations = { + items: [ + { + categories: [THREAT_INTELLIGENCE_CATEGORY], + id: '123', + status: INSTALLATION_STATUS.Installed, + }, + ], + }; + const { result, waitFor } = renderUseQuery(mockIntegrations); + + await waitFor(() => result.current.isSuccess); + + expect(result.current.isLoading).toBeFalsy(); + expect(result.current.data).toEqual(mockIntegrations); + }); +}); diff --git a/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.ts b/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.ts new file mode 100644 index 0000000000000..a5d1f8f45bdcd --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/hooks/use_integrations.ts @@ -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 { useQuery, useQueryClient } from '@tanstack/react-query'; +import { filterIntegrations } from '../utils'; +import { useKibana } from './use_kibana'; + +type IntegrationInstallStatus = 'installed' | 'installing' | 'install_failed'; + +const INTEGRATIONS_URL = '/api/fleet/epm/packages'; + +const INTEGRATIONS_CALL_TIMEOUT = 2000; + +export interface IntegrationResponse { + items: Integration[]; +} + +export interface Integration { + categories: string[]; + id: string; + status: IntegrationInstallStatus; +} + +/** + * Retrieves integrations from the Fleet plugin endpoint /api/fleet/epm/packages. + * The integrations are then filtered, and we only keep the installed ones, + * with category threat_intel and excluding the ti_utils integration. + * We cancel the query in case it's taking too long to not block the Indicators page for the user. + */ +export const useIntegrations = () => { + const { http } = useKibana().services; + const queryKey = ['integrations']; + + // retrieving the list of integrations from the fleet plugin's endpoint + const fetchIntegrations = () => http.get(INTEGRATIONS_URL); + + const query = useQuery(queryKey, fetchIntegrations, { + select: (data: IntegrationResponse) => (data ? filterIntegrations(data.items) : []), + }); + + const queryClient = useQueryClient(); + + // cancel slow integrations call to unblock the UI + setTimeout(() => queryClient.cancelQueries(queryKey), INTEGRATIONS_CALL_TIMEOUT); + + return query; +}; diff --git a/x-pack/plugins/threat_intelligence/public/modules/indicators/pages/indicators.tsx b/x-pack/plugins/threat_intelligence/public/modules/indicators/pages/indicators.tsx index 1e1f713957fb8..f161b7ac1d85c 100644 --- a/x-pack/plugins/threat_intelligence/public/modules/indicators/pages/indicators.tsx +++ b/x-pack/plugins/threat_intelligence/public/modules/indicators/pages/indicators.tsx @@ -6,32 +6,25 @@ */ import React, { FC, VFC } from 'react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { IndicatorsBarChartWrapper } from '../components/barchart'; import { IndicatorsTable } from '../components/table'; -import { useIndicators } from '../hooks/use_indicators'; +import { useAggregatedIndicators, useIndicators, useSourcererDataView } from '../hooks'; import { DefaultPageLayout } from '../../../components/layout'; import { useFilters } from '../../query_bar'; import { FiltersGlobal } from '../../../containers/filters_global'; -import { useSourcererDataView } from '../hooks/use_sourcerer_data_view'; import { FieldTypesProvider } from '../../../containers/field_types_provider'; import { InspectorProvider } from '../../../containers/inspector'; import { useColumnSettings } from '../components/table/hooks'; -import { useAggregatedIndicators } from '../hooks/use_aggregated_indicators'; import { IndicatorsFilters } from '../containers/filters'; -import { useSecurityContext } from '../../../hooks/use_security_context'; +import { useSecurityContext } from '../../../hooks'; import { UpdateStatus } from '../../../components/update_status'; -const queryClient = new QueryClient(); - const IndicatorsPageProviders: FC = ({ children }) => ( - - - - {children} - - - + + + {children} + + ); const IndicatorsPageContent: VFC = () => { @@ -115,7 +108,3 @@ export const IndicatorsPage: VFC = () => ( ); - -// Note: This is for lazy loading -// eslint-disable-next-line import/no-default-export -export default IndicatorsPage; diff --git a/x-pack/plugins/threat_intelligence/public/plugin.tsx b/x-pack/plugins/threat_intelligence/public/plugin.tsx index 88214b3abe3f1..d1e4391edfc0a 100755 --- a/x-pack/plugins/threat_intelligence/public/plugin.tsx +++ b/x-pack/plugins/threat_intelligence/public/plugin.tsx @@ -8,9 +8,9 @@ import { CoreStart, Plugin } from '@kbn/core/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { Provider as ReduxStoreProvider } from 'react-redux'; -import React, { Suspense, VFC } from 'react'; +import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import { KibanaContextProvider } from './hooks'; +import { KibanaContextProvider } from './hooks/use_kibana'; import { SecuritySolutionPluginContext, Services, @@ -20,22 +20,12 @@ import { } from './types'; import { SecuritySolutionContext } from './containers/security_solution_context'; import { EnterpriseGuard } from './containers/enterprise_guard'; -import { SecuritySolutionPluginTemplateWrapper } from './containers/security_solution_plugin_template_wrapper'; -import { IntegrationsGuard } from './containers/integrations_guard'; interface AppProps { securitySolutionContext: SecuritySolutionPluginContext; } -const LazyIndicatorsPage = React.lazy(() => import('./modules/indicators/pages/indicators')); - -const IndicatorsPage: VFC = () => ( - - }> - - - -); +const LazyIndicatorsPageWrapper = React.lazy(() => import('./containers/indicators_page_wrapper')); /** * This is used here: @@ -51,9 +41,7 @@ export const createApp = - - - + diff --git a/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.test.ts b/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.test.ts new file mode 100644 index 0000000000000..507bdb5ca4ab2 --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Integration } from '../hooks'; +import { filterIntegrations, THREAT_INTELLIGENCE_CATEGORY, THREAT_INTELLIGENCE_UTILITIES } from '.'; + +describe('filterIntegrations', () => { + it('should empty array', async () => { + const mockIntegrations: Integration[] = []; + const result = filterIntegrations(mockIntegrations); + expect(result).toEqual(mockIntegrations); + }); + + it('should return only installed ti integrations (excluding ti_utils)', async () => { + const tiInstalledIntegration: Integration = { + categories: [THREAT_INTELLIGENCE_CATEGORY], + id: '123', + status: 'installed', + }; + const tiNotInstalledIntegration: Integration = { + categories: [THREAT_INTELLIGENCE_CATEGORY], + id: '456', + status: 'install_failed', + }; + const nonTIInstalledIntegration: Integration = { + categories: ['abc'], + id: '789', + status: 'installed', + }; + const tiUtilsIntegration: Integration = { + categories: [THREAT_INTELLIGENCE_CATEGORY], + id: THREAT_INTELLIGENCE_UTILITIES, + status: 'installed', + }; + const randomIntegration: Integration = { + categories: ['abc'], + id: 'def', + status: 'installing', + }; + const mockIntegrations: Integration[] = [ + tiInstalledIntegration, + tiNotInstalledIntegration, + nonTIInstalledIntegration, + tiUtilsIntegration, + randomIntegration, + ]; + + const result = filterIntegrations(mockIntegrations); + + expect(result).toEqual([tiInstalledIntegration]); + }); +}); diff --git a/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.ts b/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.ts new file mode 100644 index 0000000000000..075c34344cbc9 --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/utils/filter_integrations.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Integration } from '../hooks'; + +export const INSTALLATION_STATUS = { + Installed: 'installed', + Installing: 'installing', + InstallFailed: 'install_failed', + NotInstalled: 'not_installed', +}; + +export const THREAT_INTELLIGENCE_CATEGORY = 'threat_intel'; + +export const THREAT_INTELLIGENCE_UTILITIES = 'ti_util'; + +/** + * Filter an array of integrations: + * - of status `installed` + * - with `threat_intel` category + * - excluding `ti_util` integration + * + * For more details see https://github.com/elastic/security-team/issues/4374 + * + * @param integrations the response from the packages endpoint in the Fleet plugin + */ +export const filterIntegrations = (integrations: Integration[]): Integration[] => + integrations.filter( + (pkg: any) => + pkg.status === INSTALLATION_STATUS.Installed && + pkg.categories.find((category: string) => category === THREAT_INTELLIGENCE_CATEGORY) != + null && + pkg.id !== THREAT_INTELLIGENCE_UTILITIES + ); diff --git a/x-pack/plugins/threat_intelligence/public/utils/index.ts b/x-pack/plugins/threat_intelligence/public/utils/index.ts new file mode 100644 index 0000000000000..6459678cb8073 --- /dev/null +++ b/x-pack/plugins/threat_intelligence/public/utils/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 * from './filter_integrations'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0bf0d3908eeb9..7beb42271c73f 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1163,7 +1163,6 @@ "data.advancedSettings.timepicker.refreshIntervalDefaultsText": "L'intervalle d'actualisation par défaut du filtre temporel. La valeur doit être spécifiée en millisecondes.", "data.advancedSettings.timepicker.refreshIntervalDefaultsTitle": "Intervalle d'actualisation du filtre temporel", "data.advancedSettings.timepicker.thisWeek": "Cette semaine", - "data.advancedSettings.timepicker.timeDefaultsText": "L’option de filtre temporel à utiliser lorsque Kibana est démarré sans filtre", "data.advancedSettings.timepicker.timeDefaultsTitle": "Filtre temporel par défaut", "data.advancedSettings.timepicker.today": "Aujourd'hui", "data.errors.fetchError": "Vérifiez votre réseau et la configuration de votre proxy. Si le problème persiste, contactez votre administrateur réseau.", @@ -6861,7 +6860,6 @@ "xpack.apm.tutorial.config_otel.description3": "La liste exhaustive des variables d'environnement, les paramètres de ligne de commande et les extraits de code de configuration (conformes à la spécification OpenTelemetry) se trouvent dans le {otelInstrumentationGuide}. Certains clients OpenTelemetry instables peuvent ne pas prendre en charge toutes les fonctionnalités et nécessitent peut-être d'autres mécanismes de configuration.", "xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "Définir l'URL personnalisée du serveur APM (par défaut : {defaultApmServerUrl})", "xpack.apm.tutorial.djangoClient.configure.textPost": "Consultez la [documentation]({documentationLink}) pour une utilisation avancée.", - "xpack.apm.tutorial.dotNetClient.configureAgent.textPost": "Si vous ne transférez pas une instance \"IConfiguration\" à l'agent (par ex., pour les applications non ASP.NET Core) vous pouvez également configurer l'agent par le biais de variables d'environnement. \n Consultez [the documentation]({documentationLink}) pour une utilisation avancée.", "xpack.apm.tutorial.dotNetClient.download.textPre": "Ajoutez le(s) package(s) d'agent depuis [NuGet]({allNuGetPackagesLink}) à votre application .NET. Plusieurs packages NuGet sont disponibles pour différents cas d'utilisation. \n\nPour une application ASP.NET Core avec Entity Framework Core, téléchargez le package [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}). Ce package ajoutera automatiquement chaque composant d'agent à votre application. \n\n Si vous souhaitez minimiser les dépendances, vous pouvez utiliser le package [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) uniquement pour le monitoring d'ASP.NET Core ou le package [Elastic.Apm.EfCore]({efCorePackageLink}) uniquement pour le monitoring d'Entity Framework Core. \n\n Si vous souhaitez seulement utiliser l'API d'agent publique pour l'instrumentation manuelle, utilisez le package [Elastic.Apm]({elasticApmPackageLink}).", "xpack.apm.tutorial.downloadServerRpm": "Vous cherchez les packages 32 bits ? Consultez la [Download page]({downloadPageLink}).", "xpack.apm.tutorial.downloadServerTitle": "Vous cherchez les packages 32 bits ? Consultez la [Download page]({downloadPageLink}).", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 91d6ae6f2bcb5..fcc2c1c49cdf8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1161,7 +1161,6 @@ "data.advancedSettings.timepicker.refreshIntervalDefaultsText": "時間フィルターのデフォルト更新間隔「値」はミリ秒で指定する必要があります。", "data.advancedSettings.timepicker.refreshIntervalDefaultsTitle": "タイムピッカーの更新間隔", "data.advancedSettings.timepicker.thisWeek": "今週", - "data.advancedSettings.timepicker.timeDefaultsText": "時間フィルターが選択されずにKibanaが起動した際に使用される時間フィルターです", "data.advancedSettings.timepicker.timeDefaultsTitle": "デフォルトのタイムピッカー", "data.advancedSettings.timepicker.today": "今日", "data.errors.fetchError": "ネットワークとプロキシ構成を確認してください。問題が解決しない場合は、ネットワーク管理者に問い合わせてください。", @@ -6849,7 +6848,6 @@ "xpack.apm.tutorial.config_otel.description3": "環境変数、コマンドラインパラメーター、構成コードスニペット(OpenTelemetry仕様に準拠)の網羅的な一覧は、{otelInstrumentationGuide}をご覧ください。一部の不安定なOpenTelemetryクライアントでは、一部の機能がサポートされておらず、別の構成メカニズムが必要になる場合があります。", "xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL(デフォルト:{defaultApmServerUrl})を設定します", "xpack.apm.tutorial.djangoClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション]({documentationLink})をご覧ください。", - "xpack.apm.tutorial.dotNetClient.configureAgent.textPost": "エージェントに「IConfiguration」インスタンスが渡されていない場合、(例:非 ASP.NET Core アプリケーションの場合)、エージェントを環境変数で構成することもできます。\n 高度な用途に関しては [ドキュメンテーション]({documentationLink})をご覧ください。", "xpack.apm.tutorial.dotNetClient.download.textPre": "[NuGet]({allNuGetPackagesLink})から .NET アプリケーションにエージェントパッケージを追加してください。用途の異なる複数の NuGet パッケージがあります。\n\nEntity Framework Core の ASP.NET Core アプリケーションの場合は、[Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink})パッケージをダウンロードしてください。このパッケージは、自動的にすべてのエージェントコンポーネントをアプリケーションに追加します。\n\n 依存性を最低限に抑えたい場合、ASP.NET Coreの監視のみに[Elastic.Apm.AspNetCore]({aspNetCorePackageLink})パッケージ、またはEntity Framework Coreの監視のみに[Elastic.Apm.EfCore]({efCorePackageLink})パッケージを使用することができます。\n\n 手動インストルメンテーションのみにパブリック Agent API を使用する場合は、[Elastic.Apm]({elasticApmPackageLink})パッケージを使用してください。", "xpack.apm.tutorial.downloadServerRpm": "32 ビットパッケージをお探しですか?[ダウンロードページ]({downloadPageLink})をご覧ください。", "xpack.apm.tutorial.downloadServerTitle": "32 ビットパッケージをお探しですか?[ダウンロードページ]({downloadPageLink})をご覧ください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index c929f0f0d80ba..ff49a2cd73d6c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1163,7 +1163,6 @@ "data.advancedSettings.timepicker.refreshIntervalDefaultsText": "时间筛选的默认刷新时间间隔。需要使用毫秒单位指定“值”。", "data.advancedSettings.timepicker.refreshIntervalDefaultsTitle": "时间筛选刷新时间间隔", "data.advancedSettings.timepicker.thisWeek": "本周", - "data.advancedSettings.timepicker.timeDefaultsText": "在未使用时间筛选的情况下启动 Kibana 时要使用的时间筛选选项", "data.advancedSettings.timepicker.timeDefaultsTitle": "时间筛选默认值", "data.advancedSettings.timepicker.today": "今日", "data.errors.fetchError": "请检查您的网络和代理配置。如果问题持续存在,请联系网络管理员。", @@ -6865,7 +6864,6 @@ "xpack.apm.tutorial.config_otel.description3": "{otelInstrumentationGuide}中提供了环境变量、命令行参数和配置代码片段(根据 OpenTelemetry 规范)的详细列表。某些不稳定的 OpenTelemetry 客户端可能不支持所有功能,并可能需要备选配置机制。", "xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "设置定制 APM Server URL(默认值:{defaultApmServerUrl})", "xpack.apm.tutorial.djangoClient.configure.textPost": "有关高级用法,请参阅[文档]({documentationLink})。", - "xpack.apm.tutorial.dotNetClient.configureAgent.textPost": "如果您未将 `IConfiguration` 实例传递给代理(例如非 ASP.NET Core 应用程序), 您还可以通过环境变量配置代理。\n 有关高级用法,请参阅[文档]({documentationLink})。", "xpack.apm.tutorial.dotNetClient.download.textPre": "将来自 [NuGet]({allNuGetPackagesLink}) 的代理软件包添加到 .NET 应用程序。有多个 NuGet 软件包可用于不同的用例。\n\n对于具有 Entity Framework Core 的 ASP.NET Core 应用程序,请下载 [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) 软件包。此软件包将自动将每个 代理组件添加到您的应用程序。\n\n 如果您希望最大程度减少依存关系,您可以将 [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) 软件包仅用于 ASP.NET Core 监测,或将 [Elastic.Apm.EfCore]({efCorePackageLink}) 软件包仅用于 Entity Framework Core 监测。\n\n 如果 仅希望将公共代理 API 用于手动检测,请使用 [Elastic.Apm]({elasticApmPackageLink}) 软件包。", "xpack.apm.tutorial.downloadServerRpm": "寻找 32 位软件包?请参阅[下载页面]({downloadPageLink})。", "xpack.apm.tutorial.downloadServerTitle": "寻找 32 位软件包?请参阅[下载页面]({downloadPageLink})。", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index 0112f2296ee05..f937663cd27a3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -181,7 +181,7 @@ describe('action_type_form', () => { // Verify that the tooltip renders // Use fake timers so we don't have to wait for the EuiToolTip timeout - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); wrapper.find('[data-test-subj="action-group-error-icon"]').first().simulate('mouseOver'); // Run the timers so the EuiTooltip will be visible jest.runAllTimers(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/field_browser/components/field_name/field_name.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/field_browser/components/field_name/field_name.test.tsx index 8a0b52b082ea9..1fafae26032c0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/field_browser/components/field_name/field_name.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/field_browser/components/field_name/field_name.test.tsx @@ -18,7 +18,7 @@ const defaultProps = { describe('FieldName', () => { beforeEach(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); test('it renders the field name', () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx index dfebee8e5d6ff..58ca1fb0193cd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx @@ -232,7 +232,7 @@ describe('rule_edit', () => { it('should render an alert icon next to save button stating the potential change in permissions', async () => { // Use fake timers so we don't have to wait for the EuiToolTip timeout - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); await setup(); expect(wrapper.find('[data-test-subj="changeInPrivilegesTip"]').exists()).toBeTruthy(); @@ -241,7 +241,7 @@ describe('rule_edit', () => { }); // Run the timers so the EuiTooltip will be visible - jest.runAllTimers(); + jest.runOnlyPendingTimers(); wrapper.update(); expect(wrapper.find('.euiToolTipPopover').text()).toBe( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx index 6bfe953e28696..39613e456157d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx @@ -1106,7 +1106,7 @@ describe('rules_list component with items', () => { it('renders table of rules', async () => { // Use fake timers so we don't have to wait for the EuiToolTip timeout - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); await setup(); expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(mockedRulesData.length); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecation_logs/es_deprecation_logs.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecation_logs/es_deprecation_logs.test.tsx index f4b07c6f2f5ad..6de4d8095d267 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecation_logs/es_deprecation_logs.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecation_logs/es_deprecation_logs.test.tsx @@ -361,7 +361,7 @@ describe('ES deprecation logs', () => { describe('Poll for logs count', () => { beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // First request should make the step be complete httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts index 457c0c4ec2be5..3af99109510a8 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts @@ -103,9 +103,9 @@ describe('ES deprecations table', () => { (deprecation) => deprecation.isCritical === false ); - expect(find('criticalDeprecationsCount').text()).toContain(criticalDeprecations.length); + expect(find('criticalDeprecationsCount').text()).toContain(String(criticalDeprecations.length)); - expect(find('warningDeprecationsCount').text()).toContain(warningDeprecations.length); + expect(find('warningDeprecationsCount').text()).toContain(String(warningDeprecations.length)); }); describe('remote clusters callout', () => { diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts index 845141fb7784f..f181aef4f7c05 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts @@ -27,7 +27,7 @@ describe('Reindex deprecation flyout', () => { let testBed: ElasticsearchTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/time_manipulation.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/time_manipulation.ts index 65cec19549736..9789fa3a8f52e 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/time_manipulation.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/time_manipulation.ts @@ -8,7 +8,7 @@ import { act } from 'react-dom/test-utils'; /** - * These helpers are intended to be used in conjunction with jest.useFakeTimers(). + * These helpers are intended to be used in conjunction with jest.useFakeTimers('legacy'). */ const flushPromiseJobQueue = async () => { diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/deprecations_table/deprecations_table.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/deprecations_table/deprecations_table.test.ts index 7a62fa33bb876..e4c85d47bc464 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/deprecations_table/deprecations_table.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/deprecations_table/deprecations_table.test.ts @@ -69,10 +69,10 @@ describe('Kibana deprecations - Deprecations table', () => { const { find } = testBed; expect(find('criticalDeprecationsCount').text()).toContain( - mockedCriticalKibanaDeprecations.length + String(mockedCriticalKibanaDeprecations.length) ); expect(find('warningDeprecationsCount').text()).toContain( - mockedWarningKibanaDeprecations.length + String(mockedWarningKibanaDeprecations.length) ); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx index 688e060705ee4..bc93c05fb7e7a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx @@ -153,7 +153,7 @@ describe('Overview - Backup Step', () => { describe('poll for new status', () => { beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // First request will succeed. httpRequestsMockHelpers.setLoadCloudBackupStatusResponse({ diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/kibana_deprecation_issues.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/kibana_deprecation_issues.test.tsx index 77c8a9e998edf..cead46f258c4a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/kibana_deprecation_issues.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/kibana_deprecation_issues.test.tsx @@ -57,8 +57,8 @@ describe('Overview - Fix deprecation issues step - Kibana deprecations', () => { const { exists, find } = testBed; expect(exists('kibanaStatsPanel')).toBe(true); - expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain(1); - expect(find('kibanaStatsPanel.warningDeprecations').text()).toContain(2); + expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain('1'); + expect(find('kibanaStatsPanel.warningDeprecations').text()).toContain('2'); }); test('panel links to Kibana deprecations page', () => { @@ -77,7 +77,7 @@ describe('Overview - Fix deprecation issues step - Kibana deprecations', () => { const { exists, find } = testBed; expect(exists('kibanaStatsPanel')).toBe(true); - expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain(1); + expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain('1'); expect(exists('kibanaStatsPanel.noWarningDeprecationIssues')).toBe(true); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/migrate_system_indices/step_completion.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/migrate_system_indices/step_completion.test.ts index cbece74355d6d..9c69b4bb18475 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/migrate_system_indices/step_completion.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/migrate_system_indices/step_completion.test.ts @@ -55,7 +55,7 @@ describe('Overview - Migrate system indices - Step completion', () => { describe('Poll for new status', () => { beforeEach(async () => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); // First request should make the step be incomplete httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus({ diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts index 54352e278770b..b7e80808cfb82 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts @@ -21,7 +21,7 @@ describe(' create route', () => { let testBed: WatchCreateJsonTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx index 4fe5fb3445da8..3395e8d95de7c 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx @@ -84,7 +84,7 @@ describe(' create route', () => { let testBed: WatchCreateThresholdTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.ts index f57dcb6788fe1..f392806b854ff 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.ts @@ -21,7 +21,7 @@ describe('', () => { let testBed: WatchEditTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts index b856002775188..995b363504685 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts @@ -18,7 +18,7 @@ describe('', () => { let testBed: WatchListTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts index 1d00b6c699721..3ae7415630750 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts @@ -45,7 +45,7 @@ describe('', () => { let testBed: WatchStatusTestBed; beforeAll(() => { - jest.useFakeTimers(); + jest.useFakeTimers('legacy'); }); afterAll(() => { diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 090e48f7a8a2d..d2831b61799f5 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -197,6 +197,18 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, `--xpack.actions.preconfiguredAlertHistoryEsIndex=${preconfiguredAlertHistoryEsIndex}`, `--xpack.actions.preconfigured=${JSON.stringify({ + 'my-test-email': { + actionTypeId: '.email', + name: 'TestEmail#xyz', + config: { + from: 'me@test.com', + service: '__json', + }, + secrets: { + user: 'user', + password: 'password', + }, + }, 'my-slack1': { actionTypeId: '.slack', name: 'Slack#xyz', diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts index ae874d942e75b..316d1916b4af2 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts @@ -7,10 +7,13 @@ import http from 'http'; import https from 'https'; -import { Plugin, CoreSetup, IRouter } from '@kbn/core/server'; +import { Plugin, CoreSetup } from '@kbn/core/server'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; -import { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server/plugin'; +import { + PluginSetupContract as ActionsPluginSetupContract, + PluginStartContract as ActionsPluginStartContract, +} from '@kbn/actions-plugin/server/plugin'; import { ActionType } from '@kbn/actions-plugin/server'; import { initPlugin as initPagerduty } from './pagerduty_simulation'; import { initPlugin as initSwimlane } from './swimlane_simulation'; @@ -22,6 +25,7 @@ import { initPlugin as initSlack } from './slack_simulation'; import { initPlugin as initWebhook } from './webhook_simulation'; import { initPlugin as initMSExchange } from './ms_exchage_server_simulation'; import { initPlugin as initXmatters } from './xmatters_simulation'; +import { initPlugin as initUnsecuredAction } from './unsecured_actions_simulation'; export const NAME = 'actions-FTS-external-service-simulators'; @@ -82,8 +86,9 @@ interface FixtureSetupDeps { features: FeaturesPluginSetup; } -interface FixtureStartDeps { +export interface FixtureStartDeps { encryptedSavedObjects: EncryptedSavedObjectsPluginStart; + actions: ActionsPluginStartContract; } export class FixturePlugin implements Plugin { @@ -126,7 +131,7 @@ export class FixturePlugin implements Plugin) { + router.post( + { + path: `/api/sample_unsecured_action`, + validate: { + body: schema.object({ + requesterId: schema.string(), + id: schema.string(), + params: schema.recordOf(schema.string(), schema.any()), + }), + }, + }, + async function ( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + const [_, { actions }] = await coreSetup.getStartServices(); + const { body } = req; + + try { + const unsecuredActionsClient = actions.getUnsecuredActionsClient(); + const { requesterId, id, params } = body; + await unsecuredActionsClient.bulkEnqueueExecution(requesterId, [{ id, params }]); + + return res.ok({ body: { status: 'success' } }); + } catch (err) { + return res.ok({ body: { status: 'error', error: `${err}` } }); + } + } + ); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_delete.ts new file mode 100644 index 0000000000000..91de3084993ff --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_delete.ts @@ -0,0 +1,563 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { UserAtSpaceScenarios, SuperuserAtSpace1 } from '../../../scenarios'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; + +const defaultSuccessfulResponse = { errors: [], total: 1, taskIdsFailedToBeDeleted: [] }; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('bulkDelete', () => { + const objectRemover = new ObjectRemover(supertest); + + after(() => objectRemover.removeAll()); + + const getScheduledTask = async (id: string) => { + return await es.get({ + id: `task:${id}`, + index: '.kibana_task_manager', + }); + }; + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + + describe(scenario.id, () => { + afterEach(() => objectRemover.removeAll()); + it('should handle bulk delete of one rule appropriately based on id', async () => { + const { body: createdRule1 } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: [createdRule1.id] }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to bulkDelete a "test.noop" rule for "alertsFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'space_1_all_alerts_none_actions at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql(defaultSuccessfulResponse); + expect(response.statusCode).to.eql(200); + try { + await getScheduledTask(createdRule1.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle bulk delete of one rule appropriately based on id when consumer is the same as producer', async () => { + const { body: createdRule1 } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }) + ) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: [createdRule1.id] }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: + 'Unauthorized to bulkDelete a "test.restricted-noop" rule for "alertsRestrictedFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: 'No rules found for bulk delete', + }); + expect(response.statusCode).to.eql(400); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'superuser at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql(defaultSuccessfulResponse); + expect(response.statusCode).to.eql(200); + try { + await getScheduledTask(createdRule1.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle delete alert request appropriately when consumer is not the producer', async () => { + const { body: createdRule1 } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.restricted-noop', + consumer: 'alertsFixture', + }) + ) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: [createdRule1.id] }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + case 'global_read at space1': + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: 'No rules found for bulk delete', + }); + expect(response.statusCode).to.eql(400); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'superuser at space1': + expect(response.body).to.eql(defaultSuccessfulResponse); + expect(response.statusCode).to.eql(200); + try { + await getScheduledTask(createdRule1.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle delete alert request appropriately when consumer is "alerts"', async () => { + const { body: createdRule1 } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.noop', + consumer: 'alerts', + }) + ) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: [createdRule1.id] }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to bulkDelete a "test.noop" rule by "alertsFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + // Ensure task still exists + await getScheduledTask(createdRule1.scheduled_task_id); + break; + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql(defaultSuccessfulResponse); + expect(response.statusCode).to.eql(200); + try { + await getScheduledTask(createdRule1.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle bulk delete of several rules ids appropriately based on ids', async () => { + const rules = await Promise.all( + Array.from({ length: 3 }).map(() => + supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData({ tags: ['multiple-rules-edit'] })) + .expect(200) + ) + ); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: rules.map((rule) => rule.body.id) }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + await Promise.all( + rules.map((rule) => { + objectRemover.add(space.id, rule.body.id, 'rule', 'alerting'); + return getScheduledTask(rule.body.scheduled_task_id); + }) + ); + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to bulkDelete a "test.noop" rule for "alertsFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + await Promise.all( + rules.map((rule) => { + objectRemover.add(space.id, rule.body.id, 'rule', 'alerting'); + return getScheduledTask(rule.body.scheduled_task_id); + }) + ); + break; + case 'space_1_all_alerts_none_actions at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql({ ...defaultSuccessfulResponse, total: 3 }); + expect(response.statusCode).to.eql(200); + for (const rule of rules) { + try { + await getScheduledTask(rule.body.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle bulk delete of several rules ids appropriately based on filter', async () => { + const rules = await Promise.all( + Array.from({ length: 3 }).map(() => + supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData({ tags: ['multiple-rules-delete'] })) + .expect(200) + ) + ); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ filter: `alert.attributes.tags: "multiple-rules-delete"` }) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + await Promise.all( + rules.map((rule) => { + objectRemover.add(space.id, rule.body.id, 'rule', 'alerting'); + return getScheduledTask(rule.body.scheduled_task_id); + }) + ); + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to bulkDelete a "test.noop" rule for "alertsFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + await Promise.all( + rules.map((rule) => { + objectRemover.add(space.id, rule.body.id, 'rule', 'alerting'); + return getScheduledTask(rule.body.scheduled_task_id); + }) + ); + break; + case 'space_1_all_alerts_none_actions at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql({ ...defaultSuccessfulResponse, total: 3 }); + expect(response.statusCode).to.eql(200); + for (const rule of rules) { + try { + await getScheduledTask(rule.body.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + } + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should not delete rule from another space', async () => { + const { body: createdRule } = await supertest + .post(`${getUrlPrefix('other')}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix('other')}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send({ ids: [createdRule.id] }); + + switch (scenario.id) { + // This superuser has more privileges that we think + case 'superuser at space1': + expect(response.body).to.eql(defaultSuccessfulResponse); + expect(response.statusCode).to.eql(200); + try { + await getScheduledTask(createdRule.scheduled_task_id); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.meta.statusCode).to.eql(404); + } + break; + case 'global_read at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to bulkDelete a "test.noop" rule for "alertsFixture"', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + objectRemover.add('other', createdRule.id, 'rule', 'alerting'); + await getScheduledTask(createdRule.scheduled_task_id); + break; + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.body).to.eql({ + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }); + expect(response.statusCode).to.eql(403); + expect(response.statusCode).to.eql(403); + objectRemover.add('other', createdRule.id, 'rule', 'alerting'); + await getScheduledTask(createdRule.scheduled_task_id); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + + describe('Validation tests', () => { + const { user, space } = SuperuserAtSpace1; + it('should throw an error when bulk delete of rules when both ids and filter supplied in payload', async () => { + const { body: createdRule1 } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData({ tags: ['foo'] })) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ filter: 'fake_filter', ids: [createdRule1.id] }) + .auth(user.username, user.password); + + expect(response.statusCode).to.eql(400); + expect(response.body.message).to.eql( + "Both 'filter' and 'ids' are supplied. Define either 'ids' or 'filter' properties in method's arguments" + ); + objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + await getScheduledTask(createdRule1.scheduled_task_id); + }); + + it('should return an error if we pass more than 1000 ids', async () => { + const ids = [...Array(1001)].map((_, i) => `rule${i}`); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids }) + .auth(user.username, user.password); + + expect(response.body).to.eql({ + error: 'Bad Request', + message: '[request body.ids]: array size is [1001], but cannot be greater than [1000]', + statusCode: 400, + }); + }); + + it('should return an error if we do not pass any arguments', async () => { + await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()) + .expect(200); + + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({}) + .auth(user.username, user.password); + + expect(response.body).to.eql({ + error: 'Bad Request', + message: "Either 'ids' or 'filter' property in method's arguments should be provided", + statusCode: 400, + }); + }); + + it('should return an error if we pass empty ids array', async () => { + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ ids: [] }) + .auth(user.username, user.password); + + expect(response.body).to.eql({ + error: 'Bad Request', + message: '[request body.ids]: array size is [0], but cannot be smaller than [1]', + statusCode: 400, + }); + }); + + it('should return an error if we pass empty string instead of fiter', async () => { + const response = await supertestWithoutAuth + .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) + .set('kbn-xsrf', 'foo') + .send({ filter: '' }) + .auth(user.username, user.password); + + expect(response.body).to.eql({ + error: 'Bad Request', + message: "Either 'ids' or 'filter' property in method's arguments should be provided", + statusCode: 400, + }); + }); + }); + }); +}; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts index 53b7e8e3fb2c0..6265cb7d34ff9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts @@ -31,6 +31,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./get_alert_summary')); loadTestFile(require.resolve('./rule_types')); loadTestFile(require.resolve('./bulk_edit')); + loadTestFile(require.resolve('./bulk_delete')); loadTestFile(require.resolve('./retain_api_key')); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/get_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/get_all.ts index 69f618c804eb1..d4bfe3cbdd704 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/get_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/get_all.ts @@ -127,6 +127,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referenced_by_count: 0, }, + { + id: 'my-test-email', + is_preconfigured: true, + is_deprecated: false, + connector_type_id: '.email', + name: 'TestEmail#xyz', + referenced_by_count: 0, + }, ]); break; default: @@ -262,6 +270,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referenced_by_count: 0, }, + { + id: 'my-test-email', + is_preconfigured: true, + is_deprecated: false, + connector_type_id: '.email', + name: 'TestEmail#xyz', + referenced_by_count: 0, + }, ]); break; default: @@ -361,6 +377,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referenced_by_count: 0, }, + { + id: 'my-test-email', + is_preconfigured: true, + is_deprecated: false, + connector_type_id: '.email', + name: 'TestEmail#xyz', + referenced_by_count: 0, + }, ]); break; default: diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts index b4cb36ab59d85..707f15534e663 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts @@ -571,7 +571,7 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F expect(taskState).not.to.be(undefined); actionsTelemetry = JSON.parse(taskState!); expect(actionsTelemetry.runs).to.equal(2); - expect(actionsTelemetry.count_total).to.equal(19); + expect(actionsTelemetry.count_total).to.equal(20); }); // request alerting telemetry task to run diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts b/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts index ae8d52ecd5313..91d809bff04ca 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts @@ -196,7 +196,7 @@ const NoKibanaPrivilegesAtSpace1: NoKibanaPrivilegesAtSpace1 = { interface SuperuserAtSpace1 extends Scenario { id: 'superuser at space1'; } -const SuperuserAtSpace1: SuperuserAtSpace1 = { +export const SuperuserAtSpace1: SuperuserAtSpace1 = { id: 'superuser at space1', user: Superuser, space: Space1, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/get_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/get_all.ts index 0632f48ed6e8d..7846c9512867e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/get_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/get_all.ts @@ -115,6 +115,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referenced_by_count: 0, }, + { + id: 'my-test-email', + is_preconfigured: true, + is_deprecated: false, + connector_type_id: '.email', + name: 'TestEmail#xyz', + referenced_by_count: 0, + }, ]); }); @@ -202,6 +210,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referenced_by_count: 0, }, + { + id: 'my-test-email', + is_preconfigured: true, + is_deprecated: false, + connector_type_id: '.email', + name: 'TestEmail#xyz', + referenced_by_count: 0, + }, ]); }); @@ -302,6 +318,14 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { name: 'Test:_Preconfigured_Index_Record', referencedByCount: 0, }, + { + id: 'my-test-email', + isPreconfigured: true, + isDeprecated: false, + actionTypeId: '.email', + name: 'TestEmail#xyz', + referencedByCount: 0, + }, ]); }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts index 866f13ed5294c..b4dbb42e8f993 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts @@ -28,6 +28,7 @@ export default function actionsTests({ loadTestFile, getService }: FtrProviderCo loadTestFile(require.resolve('./connector_types/stack/webhook')); loadTestFile(require.resolve('./connector_types/stack/preconfigured_alert_history_connector')); loadTestFile(require.resolve('./type_not_enabled')); + loadTestFile(require.resolve('./schedule_unsecured_action')); // note that this test will destroy existing spaces loadTestFile(require.resolve('./migrations')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/schedule_unsecured_action.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/schedule_unsecured_action.ts new file mode 100644 index 0000000000000..9a5719b7fa700 --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/schedule_unsecured_action.ts @@ -0,0 +1,191 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { SearchTotalHits } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { Spaces } from '../../scenarios'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { getUrlPrefix, ObjectRemover } from '../../../common/lib'; + +// eslint-disable-next-line import/no-default-export +export default function createUnsecuredActionTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); + const es = getService('es'); + const retry = getService('retry'); + + describe('schedule unsecured action', () => { + const objectRemover = new ObjectRemover(supertest); + + // need to wait for kibanaServer to settle ... + before(() => { + kibanaServer.resolveUrl(`/api/sample_unsecured_action`); + }); + + after(() => objectRemover.removeAll()); + + it('should successfully schedule email action', async () => { + const testStart = new Date().toISOString(); + const { body: result } = await supertest + .post(`/api/sample_unsecured_action`) + .set('kbn-xsrf', 'xxx') + .send({ + requesterId: 'functional_tester', + id: 'my-test-email', + params: { + to: ['you@test.com'], + subject: 'hello from Kibana!', + message: 'does this work??', + }, + }) + .expect(200); + expect(result.status).to.eql('success'); + + await retry.try(async () => { + const searchResult = await es.search({ + index: '.kibana-event-log*', + body: { + query: { + bool: { + filter: [ + { + term: { + 'event.provider': { + value: 'actions', + }, + }, + }, + { + term: { + 'event.action': 'execute', + }, + }, + { + range: { + '@timestamp': { + gte: testStart, + }, + }, + }, + { + nested: { + path: 'kibana.saved_objects', + query: { + bool: { + filter: [ + { + term: { + 'kibana.saved_objects.id': { + value: 'my-test-email', + }, + }, + }, + { + term: { + 'kibana.saved_objects.type': 'action', + }, + }, + ], + }, + }, + }, + }, + ], + }, + }, + }, + }); + expect((searchResult.hits.total as SearchTotalHits).value).to.eql(1); + + const hit = searchResult.hits.hits[0]; + // @ts-expect-error _source: unknown + expect(hit?._source?.event?.outcome).to.eql('success'); + // @ts-expect-error _source: unknown + expect(hit?._source?.message).to.eql( + `action executed: .email:my-test-email: TestEmail#xyz` + ); + }); + }); + + it('should not allow scheduling email action from unallowed requester', async () => { + const { body: result } = await supertest + .post(`/api/sample_unsecured_action`) + .set('kbn-xsrf', 'xxx') + .send({ + requesterId: 'not_allowed', + id: 'my-test-email', + params: { + to: ['you@test.com'], + subject: 'hello from Kibana!', + message: 'does this work??', + }, + }) + .expect(200); + expect(result.status).to.eql('error'); + expect(result.error).to.eql( + `Error: "not_allowed" feature is not allow-listed for UnsecuredActionsClient access.` + ); + }); + + it('should not allow scheduling action from unallowed connector types', async () => { + const { body: result } = await supertest + .post(`/api/sample_unsecured_action`) + .set('kbn-xsrf', 'xxx') + .send({ + requesterId: 'functional_tester', + id: 'my-slack1', + params: { + message: 'does this work??', + }, + }) + .expect(200); + expect(result.status).to.eql('error'); + expect(result.error).to.eql( + `Error: .slack actions cannot be scheduled for unsecured actions execution` + ); + }); + + it('should not allow scheduling action from non preconfigured connectors', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'My email action', + connector_type_id: '.email', + config: { + from: 'me@test.com', + service: '__json', + }, + secrets: { + user: 'user', + password: 'password', + }, + }); + expect(response.status).to.eql(200); + + const connectorId = response.body.id; + objectRemover.add(Spaces.space1.id, connectorId, 'action', 'actions'); + const { body: result } = await supertest + .post(`/api/sample_unsecured_action`) + .set('kbn-xsrf', 'xxx') + .send({ + requesterId: 'functional_tester', + id: connectorId, + params: { + to: ['you@test.com'], + subject: 'hello from Kibana!', + message: 'does this work??', + }, + }) + .expect(200); + expect(result.status).to.eql('error'); + expect(result.error).to.eql( + `Error: ${connectorId} are not preconfigured connectors and can't be scheduled for unsecured actions execution` + ); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index 78fb376fa89b8..8b98fc9422c06 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -107,9 +107,9 @@ export function createTestConfig(config: ApmFtrConfig) { kibanaServer, username: ApmUsername.apmManageOwnAndCreateAgentKeys, }), - monitorIndicesUser: await getApmApiClient({ + monitorClusterAndIndicesUser: await getApmApiClient({ kibanaServer, - username: ApmUsername.apmMonitorIndices, + username: ApmUsername.apmMonitorClusterAndIndices, }), }; }, diff --git a/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/metrics_charts.spec.ts similarity index 100% rename from x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.spec.ts rename to x-pack/test/apm_api_integration/tests/metrics/metrics_charts.spec.ts diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/generate_data.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/generate_data.ts new file mode 100644 index 0000000000000..07648d4e548a2 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/generate_data.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; + +export const config = { + memoryTotal: 536870912, // 0.5gb + memoryFree: 94371840, // ~0.08 gb + billedDurationMs: 4000, + faasTimeoutMs: 10000, + coldStartDurationPython: 4000, + faasDuration: 4000, + transactionDuration: 1000, + pythonServerlessFunctionNames: ['fn-lambda-python', 'fn-lambda-python-2'], + pythonInstanceName: 'instance_A', + serverlessId: 'arn:aws:lambda:us-west-2:001:function:', +}; + +export const expectedValues = { + expectedMemoryUsedRate: (config.memoryTotal - config.memoryFree) / config.memoryTotal, + expectedMemoryUsed: config.memoryTotal - config.memoryFree, +}; + +export async function generateData({ + synthtraceEsClient, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + start: number; + end: number; +}) { + const { + memoryTotal, + memoryFree, + billedDurationMs, + faasTimeoutMs, + coldStartDurationPython, + faasDuration, + transactionDuration, + pythonServerlessFunctionNames, + pythonInstanceName, + } = config; + + const cloudFields = { + 'cloud.provider': 'aws', + 'cloud.service.name': 'lambda', + 'cloud.region': 'us-west-2', + }; + + const [instanceLambdaPython, instanceLambdaPython2] = pythonServerlessFunctionNames.map( + (functionName) => { + return apm + .serverlessFunction({ + serviceName: 'lambda-python', + environment: 'test', + agentName: 'python', + functionName, + }) + .instance({ instanceName: pythonInstanceName, ...cloudFields }); + } + ); + + const instanceLambdaNode = apm + .serverlessFunction({ + serviceName: 'lambda-node', + environment: 'test', + agentName: 'nodejs', + functionName: 'fn-lambda-node', + }) + .instance({ instanceName: 'instance_B', ...cloudFields }); + + const systemMemory = { + free: memoryFree, + total: memoryTotal, + }; + + const transactionsEvents = timerange(start, end) + .ratePerMinute(1) + .generator((timestamp) => [ + instanceLambdaPython + .invocation() + .billedDuration(billedDurationMs) + .coldStart(true) + .coldStartDuration(coldStartDurationPython) + .faasDuration(faasDuration) + .faasTimeout(faasTimeoutMs) + .memory(systemMemory) + .timestamp(timestamp) + .duration(transactionDuration) + .success(), + instanceLambdaPython2 + .invocation() + .billedDuration(billedDurationMs) + .coldStart(true) + .coldStartDuration(coldStartDurationPython) + .faasDuration(faasDuration) + .faasTimeout(faasTimeoutMs) + .memory(systemMemory) + .timestamp(timestamp) + .duration(transactionDuration) + .success(), + instanceLambdaNode + .invocation() + .billedDuration(billedDurationMs) + .coldStart(false) + .faasDuration(faasDuration) + .faasTimeout(faasTimeoutMs) + .memory(systemMemory) + .timestamp(timestamp) + .duration(transactionDuration) + .success(), + ]); + + await synthtraceEsClient.index(transactionsEvents); +} diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_active_instances.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_active_instances.spec.ts new file mode 100644 index 0000000000000..4861313c377f1 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_active_instances.spec.ts @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import expect from '@kbn/expect'; +import { sumBy } from 'lodash'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { config, expectedValues, generateData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + const numberOfTransactionsCreated = 15; + + async function callApi(serviceName: string, serverlessId?: string) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances`, + params: { + path: { serviceName }, + query: { + environment: 'test', + kuery: '', + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + ...(serverlessId ? { serverlessId } : {}), + }, + }, + }); + } + + registry.when('Serverless active instances', { config: 'basic', archives: [] }, () => { + const { + memoryTotal, + billedDurationMs, + pythonServerlessFunctionNames, + faasDuration, + serverlessId, + } = config; + + const { expectedMemoryUsed } = expectedValues; + + before(async () => { + await generateData({ start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('Python service', () => { + let activeInstances: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances'>; + before(async () => { + const response = await callApi('lambda-python'); + activeInstances = response.body; + }); + + it('returns correct values for all serverless functions', () => { + pythonServerlessFunctionNames.forEach((name) => { + const activeInstanceOverview = activeInstances.activeInstances.find( + (item) => item.serverlessFunctionName === name + ); + + expect(activeInstanceOverview?.serverlessId).to.eql(`${serverlessId}${name}`); + expect(activeInstanceOverview?.serverlessDurationAvg).to.eql(faasDuration); + expect(activeInstanceOverview?.billedDurationAvg).to.eql(billedDurationMs); + expect(activeInstanceOverview?.avgMemoryUsed).to.eql(expectedMemoryUsed); + expect(activeInstanceOverview?.memorySize).to.eql(memoryTotal); + }); + }); + describe('timeseries', () => { + it('returns correct sum value', () => { + const sumValue = sumBy( + activeInstances?.timeseries?.filter((item) => item.y !== 0), + 'y' + ); + expect(sumValue).to.equal(numberOfTransactionsCreated); + }); + }); + }); + + describe('detailed metrics', () => { + let activeInstances: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances'>; + before(async () => { + const response = await callApi( + 'lambda-python', + `${serverlessId}${pythonServerlessFunctionNames[0]}` + ); + activeInstances = response.body; + }); + + it('returns correct values for all serverless functions', () => { + const activeInstanceOverview = activeInstances.activeInstances.find( + (item) => item.serverlessFunctionName === pythonServerlessFunctionNames[0] + ); + + expect(activeInstanceOverview?.serverlessId).to.eql( + `${serverlessId}${pythonServerlessFunctionNames[0]}` + ); + expect(activeInstanceOverview?.serverlessDurationAvg).to.eql(faasDuration); + expect(activeInstanceOverview?.billedDurationAvg).to.eql(billedDurationMs); + expect(activeInstanceOverview?.avgMemoryUsed).to.eql(expectedMemoryUsed); + expect(activeInstanceOverview?.memorySize).to.eql(memoryTotal); + }); + describe('timeseries', () => { + it('returns correct sum value', () => { + const sumValue = sumBy( + activeInstances?.timeseries?.filter((item) => item.y !== 0), + 'y' + ); + expect(sumValue).to.equal(numberOfTransactionsCreated); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_functions_overview.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_functions_overview.spec.ts new file mode 100644 index 0000000000000..e58df3291f492 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_functions_overview.spec.ts @@ -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 { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { config, expectedValues, generateData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + const numberOfTransactionsCreated = 15; + + async function callApi(serviceName: string) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview`, + params: { + path: { serviceName }, + query: { + environment: 'test', + kuery: '', + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, + }, + }); + } + + registry.when('Serverless functions overview', { config: 'basic', archives: [] }, () => { + const { + memoryTotal, + billedDurationMs, + pythonServerlessFunctionNames, + faasDuration, + serverlessId, + } = config; + const { expectedMemoryUsed } = expectedValues; + + before(async () => { + await generateData({ start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('Python service', () => { + let functionsOverview: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview'>; + before(async () => { + const response = await callApi('lambda-python'); + functionsOverview = response.body; + }); + it('returns correct number of serverless functions', () => { + expect( + functionsOverview.serverlessFunctionsOverview.map((item) => { + return item.serverlessFunctionName; + }) + ).to.eql(pythonServerlessFunctionNames); + }); + it('returns correct values for all serverless functions', () => { + pythonServerlessFunctionNames.forEach((name) => { + const functionOverview = functionsOverview.serverlessFunctionsOverview.find( + (item) => item.serverlessFunctionName === name + ); + + expect(functionOverview?.serverlessId).to.eql(`${serverlessId}${name}`); + expect(functionOverview?.serverlessDurationAvg).to.eql(faasDuration); + expect(functionOverview?.billedDurationAvg).to.eql(billedDurationMs); + expect(functionOverview?.coldStartCount).to.eql(numberOfTransactionsCreated); + expect(functionOverview?.avgMemoryUsed).to.eql(expectedMemoryUsed); + expect(functionOverview?.memorySize).to.eql(memoryTotal); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_metrics_charts.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_metrics_charts.spec.ts new file mode 100644 index 0000000000000..f660e218eba1b --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_metrics_charts.spec.ts @@ -0,0 +1,322 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { meanBy, sumBy } from 'lodash'; +import { Coordinate } from '@kbn/apm-plugin/typings/timeseries'; +import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { generateData, config } from './generate_data'; + +function isNotNullOrZeroCoordinate(coordinate: Coordinate) { + return coordinate.y !== null && coordinate.y !== 0; +} + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + const numberOfTransactionsCreated = 15; + + async function callApi(serviceName: string, serverlessId?: string) { + return await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services/{serviceName}/metrics/serverless/charts', + params: { + path: { serviceName }, + query: { + environment: 'test', + kuery: '', + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + ...(serverlessId ? { serverlessId } : {}), + }, + }, + }); + } + + registry.when( + 'Serverless metrics charts when data is not loaded', + { config: 'basic', archives: [] }, + () => { + let serverlessMetrics: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/charts'>; + before(async () => { + const response = await callApi('lambda-python'); + serverlessMetrics = response.body; + }); + + it('returns empty', () => { + serverlessMetrics.charts.forEach((chart) => { + expect(chart.series).to.be.empty(); + }); + }); + } + ); + + registry.when('Serverless metrics charts', { config: 'basic', archives: [] }, () => { + const { + memoryTotal, + memoryFree, + billedDurationMs, + coldStartDurationPython, + transactionDuration, + pythonServerlessFunctionNames, + serverlessId, + } = config; + + before(async () => { + await generateData({ start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('Python service', () => { + let serverlessMetrics: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/charts'>; + before(async () => { + const response = await callApi('lambda-python'); + serverlessMetrics = response.body; + }); + + it('returns all metrics chart', () => { + expect(serverlessMetrics.charts.length).to.be.greaterThan(0); + expect(serverlessMetrics.charts.map(({ title }) => title).sort()).to.eql([ + 'Cold start duration', + 'Cold starts', + 'Compute usage', + 'Lambda Duration', + 'System memory usage', + ]); + }); + + describe('Avg. Duration', () => { + const transactionDurationInMicroSeconds = transactionDuration * 1000; + [ + { title: 'Billed Duration', expectedValue: billedDurationMs * 1000 }, + { title: 'Transaction Duration', expectedValue: transactionDurationInMicroSeconds }, + ].map(({ title, expectedValue }) => + it(`returns correct ${title} value`, () => { + const avgDurationMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'avg_duration'; + }); + const series = avgDurationMetric?.series.find((item) => item.title === title); + expect(series?.overallValue).to.eql(expectedValue); + const meanValue = meanBy(series?.data.filter(isNotNullOrZeroCoordinate), 'y'); + expect(meanValue).to.eql(expectedValue); + }) + ); + }); + + let metricsChart: typeof serverlessMetrics.charts[0] | undefined; + + describe('Cold start duration', () => { + before(() => { + metricsChart = serverlessMetrics.charts.find((chart) => { + return chart.key === 'cold_start_duration'; + }); + }); + it('returns correct overall value', () => { + expect(metricsChart?.series[0].overallValue).to.equal(coldStartDurationPython * 1000); + }); + + it('returns correct mean value', () => { + const meanValue = meanBy( + metricsChart?.series[0]?.data.filter(isNotNullOrZeroCoordinate), + 'y' + ); + expect(meanValue).to.equal(coldStartDurationPython * 1000); + }); + }); + + describe('Cold start count', () => { + before(() => { + metricsChart = serverlessMetrics.charts.find((chart) => { + return chart.key === 'cold_start_count'; + }); + }); + + it('returns correct overall value', () => { + expect(metricsChart?.series[0].overallValue).to.equal( + numberOfTransactionsCreated * pythonServerlessFunctionNames.length + ); + }); + + it('returns correct sum value', () => { + const sumValue = sumBy( + metricsChart?.series[0]?.data.filter(isNotNullOrZeroCoordinate), + 'y' + ); + expect(sumValue).to.equal( + numberOfTransactionsCreated * pythonServerlessFunctionNames.length + ); + }); + }); + + describe('memory usage', () => { + const expectedFreeMemory = 1 - memoryFree / memoryTotal; + [ + { title: 'Max', expectedValue: expectedFreeMemory }, + { title: 'Average', expectedValue: expectedFreeMemory }, + ].map(({ title, expectedValue }) => + it(`returns correct ${title} value`, () => { + const memoryUsageMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'memory_usage_chart'; + }); + const series = memoryUsageMetric?.series.find((item) => item.title === title); + expect(series?.overallValue).to.eql(expectedValue); + const meanValue = meanBy(series?.data.filter(isNotNullOrZeroCoordinate), 'y'); + expect(meanValue).to.eql(expectedValue); + }) + ); + }); + + describe('Compute usage', () => { + const GBSeconds = 1024 * 1024 * 1024 * 1000; + const expectedValue = (memoryTotal * billedDurationMs) / GBSeconds; + let computeUsageMetric: typeof serverlessMetrics.charts[0] | undefined; + before(() => { + computeUsageMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'compute_usage'; + }); + }); + it('returns correct overall value', () => { + expect(computeUsageMetric?.series[0].overallValue).to.equal(expectedValue); + }); + + it('returns correct mean value', () => { + const meanValue = meanBy( + computeUsageMetric?.series[0]?.data.filter((item) => item.y !== 0), + 'y' + ); + expect(meanValue).to.equal(expectedValue); + }); + }); + }); + + describe('detailed metrics', () => { + let serverlessMetrics: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/charts'>; + before(async () => { + const response = await callApi( + 'lambda-python', + `${serverlessId}${pythonServerlessFunctionNames[0]}` + ); + serverlessMetrics = response.body; + }); + + it('returns all metrics chart', () => { + expect(serverlessMetrics.charts.length).to.be.greaterThan(0); + expect(serverlessMetrics.charts.map(({ title }) => title).sort()).to.eql([ + 'Cold start duration', + 'Cold starts', + 'Compute usage', + 'Lambda Duration', + 'System memory usage', + ]); + }); + + describe('Avg. Duration', () => { + const transactionDurationInMicroSeconds = transactionDuration * 1000; + [ + { title: 'Billed Duration', expectedValue: billedDurationMs * 1000 }, + { title: 'Transaction Duration', expectedValue: transactionDurationInMicroSeconds }, + ].map(({ title, expectedValue }) => + it(`returns correct ${title} value`, () => { + const avgDurationMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'avg_duration'; + }); + const series = avgDurationMetric?.series.find((item) => item.title === title); + expect(series?.overallValue).to.eql(expectedValue); + const meanValue = meanBy(series?.data.filter(isNotNullOrZeroCoordinate), 'y'); + expect(meanValue).to.eql(expectedValue); + }) + ); + }); + + let metricsChart: typeof serverlessMetrics.charts[0] | undefined; + + describe('Cold start duration', () => { + before(() => { + metricsChart = serverlessMetrics.charts.find((chart) => { + return chart.key === 'cold_start_duration'; + }); + }); + it('returns correct overall value', () => { + expect(metricsChart?.series[0].overallValue).to.equal(coldStartDurationPython * 1000); + }); + + it('returns correct mean value', () => { + const meanValue = meanBy( + metricsChart?.series[0]?.data.filter(isNotNullOrZeroCoordinate), + 'y' + ); + expect(meanValue).to.equal(coldStartDurationPython * 1000); + }); + }); + + describe('Cold start count', () => { + before(() => { + metricsChart = serverlessMetrics.charts.find((chart) => { + return chart.key === 'cold_start_count'; + }); + }); + + it('returns correct overall value', () => { + expect(metricsChart?.series[0].overallValue).to.equal(numberOfTransactionsCreated); + }); + + it('returns correct sum value', () => { + const sumValue = sumBy( + metricsChart?.series[0]?.data.filter(isNotNullOrZeroCoordinate), + 'y' + ); + expect(sumValue).to.equal(numberOfTransactionsCreated); + }); + }); + + describe('memory usage', () => { + const expectedFreeMemory = 1 - memoryFree / memoryTotal; + [ + { title: 'Max', expectedValue: expectedFreeMemory }, + { title: 'Average', expectedValue: expectedFreeMemory }, + ].map(({ title, expectedValue }) => + it(`returns correct ${title} value`, () => { + const memoryUsageMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'memory_usage_chart'; + }); + const series = memoryUsageMetric?.series.find((item) => item.title === title); + expect(series?.overallValue).to.eql(expectedValue); + const meanValue = meanBy(series?.data.filter(isNotNullOrZeroCoordinate), 'y'); + expect(meanValue).to.eql(expectedValue); + }) + ); + }); + + describe('Compute usage', () => { + const GBSeconds = 1024 * 1024 * 1024 * 1000; + const expectedValue = (memoryTotal * billedDurationMs) / GBSeconds; + let computeUsageMetric: typeof serverlessMetrics.charts[0] | undefined; + before(() => { + computeUsageMetric = serverlessMetrics.charts.find((chart) => { + return chart.key === 'compute_usage'; + }); + }); + it('returns correct overall value', () => { + expect(computeUsageMetric?.series[0].overallValue).to.equal(expectedValue); + }); + + it('returns correct mean value', () => { + const meanValue = meanBy( + computeUsageMetric?.series[0]?.data.filter((item) => item.y !== 0), + 'y' + ); + expect(meanValue).to.equal(expectedValue); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts new file mode 100644 index 0000000000000..eff5e11278018 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { config, expectedValues, generateData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + async function callApi(serviceName: string, serverlessId?: string) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/services/{serviceName}/metrics/serverless/summary`, + params: { + path: { serviceName }, + query: { + environment: 'test', + kuery: '', + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + ...(serverlessId ? { serverlessId } : {}), + }, + }, + }); + } + + registry.when( + 'Serverless overview when data is not loaded', + { config: 'basic', archives: [] }, + () => { + let serverlessSummary: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/summary'>; + before(async () => { + const response = await callApi('lambda-python'); + serverlessSummary = response.body; + }); + + it('returns empty', () => { + expect(serverlessSummary).to.be.empty(); + }); + } + ); + + registry.when('Serverless overview', { config: 'basic', archives: [] }, () => { + const { billedDurationMs, pythonServerlessFunctionNames, faasDuration, serverlessId } = config; + const { expectedMemoryUsedRate } = expectedValues; + + before(async () => { + await generateData({ start, end, synthtraceEsClient }); + }); + + // after(() => synthtraceEsClient.clean()); + + describe('Python service', () => { + let serverlessSummary: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/summary'>; + before(async () => { + const response = await callApi('lambda-python'); + serverlessSummary = response.body; + }); + + it('returns correct memory avg', () => { + expect(serverlessSummary.memoryUsageAvgRate).to.eql(expectedMemoryUsedRate); + }); + it('returns correct serverless function total', () => { + expect(serverlessSummary.serverlessFunctionsTotal).to.eql( + pythonServerlessFunctionNames.length + ); + }); + it('returns correct serverless duration avg', () => { + expect(serverlessSummary.serverlessDurationAvg).to.eql(faasDuration); + }); + it('returns correct billed duration avg', () => { + expect(serverlessSummary.billedDurationAvg).to.eql(billedDurationMs); + }); + }); + + describe('detailed metrics', () => { + let serverlessSummary: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/summary'>; + before(async () => { + const response = await callApi( + 'lambda-python', + `${serverlessId}${pythonServerlessFunctionNames[0]}` + ); + serverlessSummary = response.body; + }); + + it('returns correct memory avg', () => { + expect(serverlessSummary.memoryUsageAvgRate).to.eql(expectedMemoryUsedRate); + }); + it('returns correct serverless function total', () => { + expect(serverlessSummary.serverlessFunctionsTotal).to.eql(1); + }); + it('returns correct serverless duration avg', () => { + expect(serverlessSummary.serverlessDurationAvg).to.eql(faasDuration); + }); + it('returns correct billed duration avg', () => { + expect(serverlessSummary.billedDurationAvg).to.eql(billedDurationMs); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/metrics_charts/serverless.spec.ts b/x-pack/test/apm_api_integration/tests/metrics_charts/serverless.spec.ts deleted file mode 100644 index be56277b5fad1..0000000000000 --- a/x-pack/test/apm_api_integration/tests/metrics_charts/serverless.spec.ts +++ /dev/null @@ -1,431 +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 { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import { apm, timerange } from '@kbn/apm-synthtrace'; -import expect from '@kbn/expect'; -import { meanBy, sumBy } from 'lodash'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const synthtraceEsClient = getService('synthtraceEsClient'); - - const start = new Date('2021-01-01T00:00:00.000Z').getTime(); - const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; - - async function callApi(serviceName: string, agentName: string) { - return await apmApiClient.readUser({ - endpoint: `GET /internal/apm/services/{serviceName}/metrics/charts`, - params: { - path: { serviceName }, - query: { - environment: 'test', - agentName, - kuery: '', - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - serviceRuntimeName: 'aws_lambda', - }, - }, - }); - } - - registry.when( - 'Serverless metrics charts when data is loaded', - { config: 'basic', archives: [] }, - () => { - const MEMORY_TOTAL = 536870912; // 0.5gb; - const MEMORY_FREE = 94371840; // ~0.08 gb; - const BILLED_DURATION_MS = 4000; - const FAAS_TIMEOUT_MS = 10000; - const COLD_START_DURATION_PYTHON = 4000; - const COLD_START_DURATION_NODE = 0; - const FAAS_DURATION = 4000; - const TRANSACTION_DURATION = 1000; - - const numberOfTransactionsCreated = 15; - const numberOfPythonInstances = 2; - - before(async () => { - const cloudFields = { - 'cloud.provider': 'aws', - 'cloud.service.name': 'lambda', - 'cloud.region': 'us-west-2', - }; - - const instanceLambdaPython = apm - .serverlessFunction({ - serviceName: 'lambda-python', - environment: 'test', - agentName: 'python', - functionName: 'fn-lambda-python', - }) - .instance({ instanceName: 'instance python', ...cloudFields }); - - const instanceLambdaPython2 = apm - .serverlessFunction({ - serviceName: 'lambda-python', - environment: 'test', - agentName: 'python', - functionName: 'fn-lambda-python-2', - }) - .instance({ instanceName: 'instance python 2', ...cloudFields }); - - const instanceLambdaNode = apm - .serverlessFunction({ - serviceName: 'lambda-node', - environment: 'test', - agentName: 'nodejs', - functionName: 'fn-lambda-node', - }) - .instance({ instanceName: 'instance node', ...cloudFields }); - - const systemMemory = { - free: MEMORY_FREE, - total: MEMORY_TOTAL, - }; - - const transactionsEvents = timerange(start, end) - .interval('1m') - .rate(1) - .generator((timestamp) => [ - instanceLambdaPython - .invocation() - .billedDuration(BILLED_DURATION_MS) - .coldStart(true) - .coldStartDuration(COLD_START_DURATION_PYTHON) - .faasDuration(FAAS_DURATION) - .faasTimeout(FAAS_TIMEOUT_MS) - .memory(systemMemory) - .timestamp(timestamp) - .duration(TRANSACTION_DURATION) - .success(), - instanceLambdaPython2 - .invocation() - .billedDuration(BILLED_DURATION_MS) - .coldStart(true) - .coldStartDuration(COLD_START_DURATION_PYTHON) - .faasDuration(FAAS_DURATION) - .faasTimeout(FAAS_TIMEOUT_MS) - .memory(systemMemory) - .timestamp(timestamp) - .duration(TRANSACTION_DURATION) - .success(), - instanceLambdaNode - .invocation() - .billedDuration(BILLED_DURATION_MS) - .coldStart(false) - .coldStartDuration(COLD_START_DURATION_NODE) - .faasDuration(FAAS_DURATION) - .faasTimeout(FAAS_TIMEOUT_MS) - .memory(systemMemory) - .timestamp(timestamp) - .duration(TRANSACTION_DURATION) - .success(), - ]); - - await synthtraceEsClient.index(transactionsEvents); - }); - - after(() => synthtraceEsClient.clean()); - - describe('python', () => { - let metrics: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/charts'>; - before(async () => { - const { status, body } = await callApi('lambda-python', 'python'); - - expect(status).to.be(200); - metrics = body; - }); - - it('returns all metrics chart', () => { - expect(metrics.charts.length).to.be.greaterThan(0); - expect(metrics.charts.map(({ title }) => title).sort()).to.eql([ - 'Active instances', - 'Avg. Duration', - 'Cold start', - 'Cold start duration', - 'Compute usage', - 'System memory usage', - ]); - }); - - describe('Avg. Duration', () => { - const transactionDurationInMicroSeconds = TRANSACTION_DURATION * 1000; - [ - { title: 'Billed Duration', expectedValue: BILLED_DURATION_MS * 1000 }, - { title: 'Transaction Duration', expectedValue: transactionDurationInMicroSeconds }, - ].map(({ title, expectedValue }) => - it(`returns correct ${title} value`, () => { - const avgDurationMetric = metrics.charts.find((chart) => { - return chart.key === 'avg_duration'; - }); - const series = avgDurationMetric?.series.find((item) => item.title === title); - expect(series?.overallValue).to.eql(expectedValue); - const meanValue = meanBy( - series?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.eql(expectedValue); - }) - ); - }); - - describe('Cold start duration', () => { - let coldStartDurationMetric: typeof metrics['charts'][0] | undefined; - before(() => { - coldStartDurationMetric = metrics.charts.find((chart) => { - return chart.key === 'cold_start_duration'; - }); - }); - it('returns correct overall value', () => { - expect(coldStartDurationMetric?.series[0].overallValue).to.equal( - COLD_START_DURATION_PYTHON * 1000 - ); - }); - - it('returns correct mean value', () => { - const meanValue = meanBy( - coldStartDurationMetric?.series[0]?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.equal(COLD_START_DURATION_PYTHON * 1000); - }); - }); - - describe('Cold start count', () => { - let coldStartCountMetric: typeof metrics['charts'][0] | undefined; - before(() => { - coldStartCountMetric = metrics.charts.find((chart) => { - return chart.key === 'cold_start_count'; - }); - }); - - it('returns correct overall value', () => { - expect(coldStartCountMetric?.series[0].overallValue).to.equal( - numberOfTransactionsCreated * numberOfPythonInstances - ); - }); - - it('returns correct sum value', () => { - const sumValue = sumBy( - coldStartCountMetric?.series[0]?.data.filter((item) => item.y !== null), - 'y' - ); - expect(sumValue).to.equal(numberOfTransactionsCreated * numberOfPythonInstances); - }); - }); - - describe('memory usage', () => { - const expectedFreeMemory = 1 - MEMORY_FREE / MEMORY_TOTAL; - [ - { title: 'Max', expectedValue: expectedFreeMemory }, - { title: 'Average', expectedValue: expectedFreeMemory }, - ].map(({ title, expectedValue }) => - it(`returns correct ${title} value`, () => { - const memoryUsageMetric = metrics.charts.find((chart) => { - return chart.key === 'memory_usage_chart'; - }); - const series = memoryUsageMetric?.series.find((item) => item.title === title); - expect(series?.overallValue).to.eql(expectedValue); - const meanValue = meanBy( - series?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.eql(expectedValue); - }) - ); - }); - - describe('Compute usage', () => { - const GBSeconds = 1024 * 1024 * 1024 * 1000; - const expectedValue = (MEMORY_TOTAL * BILLED_DURATION_MS) / GBSeconds; - let computeUsageMetric: typeof metrics['charts'][0] | undefined; - before(() => { - computeUsageMetric = metrics.charts.find((chart) => { - return chart.key === 'compute_usage'; - }); - }); - it('returns correct overall value', () => { - expect(computeUsageMetric?.series[0].overallValue).to.equal(expectedValue); - }); - - it('returns correct mean value', () => { - const meanValue = meanBy( - computeUsageMetric?.series[0]?.data.filter((item) => item.y !== 0), - 'y' - ); - expect(meanValue).to.equal(expectedValue); - }); - }); - - describe('Active instances', () => { - let activeInstancesMetric: typeof metrics['charts'][0] | undefined; - before(() => { - activeInstancesMetric = metrics.charts.find((chart) => { - return chart.key === 'active_instances'; - }); - }); - it('returns correct overall value', () => { - expect(activeInstancesMetric?.series[0].overallValue).to.equal(numberOfPythonInstances); - }); - - it('returns correct sum value', () => { - const sumValue = sumBy( - activeInstancesMetric?.series[0]?.data.filter((item) => item.y !== 0), - 'y' - ); - expect(sumValue).to.equal(numberOfTransactionsCreated * numberOfPythonInstances); - }); - }); - }); - - describe('nodejs', () => { - let metrics: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/charts'>; - before(async () => { - const { status, body } = await callApi('lambda-node', 'nodejs'); - expect(status).to.be(200); - metrics = body; - }); - - it('returns all metrics chart', () => { - expect(metrics.charts.length).to.be.greaterThan(0); - expect(metrics.charts.map(({ title }) => title).sort()).to.eql([ - 'Active instances', - 'Avg. Duration', - 'Cold start', - 'Cold start duration', - 'Compute usage', - 'System memory usage', - ]); - }); - describe('Avg. Duration', () => { - const transactionDurationInMicroSeconds = TRANSACTION_DURATION * 1000; - [ - { title: 'Billed Duration', expectedValue: BILLED_DURATION_MS * 1000 }, - { title: 'Transaction Duration', expectedValue: transactionDurationInMicroSeconds }, - ].map(({ title, expectedValue }) => - it(`returns correct ${title} value`, () => { - const avgDurationMetric = metrics.charts.find((chart) => { - return chart.key === 'avg_duration'; - }); - const series = avgDurationMetric?.series.find((item) => item.title === title); - expect(series?.overallValue).to.eql(expectedValue); - const meanValue = meanBy( - series?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.eql(expectedValue); - }) - ); - }); - - describe('Cold start duration', () => { - let coldStartDurationMetric: typeof metrics['charts'][0] | undefined; - before(() => { - coldStartDurationMetric = metrics.charts.find((chart) => { - return chart.key === 'cold_start_duration'; - }); - }); - - it('returns 0 overall value', () => { - expect(coldStartDurationMetric?.series[0].overallValue).to.equal( - COLD_START_DURATION_NODE * 1000 - ); - }); - - it('returns 0 mean value', () => { - const meanValue = meanBy( - coldStartDurationMetric?.series[0]?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.equal(COLD_START_DURATION_NODE * 1000); - }); - }); - - describe('Cold start count', () => { - let coldStartCountMetric: typeof metrics['charts'][0] | undefined; - before(() => { - coldStartCountMetric = metrics.charts.find((chart) => { - return chart.key === 'cold_start_count'; - }); - }); - - it('does not return cold start count', () => { - expect(coldStartCountMetric?.series).to.be.empty(); - }); - }); - - describe('memory usage', () => { - const expectedFreeMemory = 1 - MEMORY_FREE / MEMORY_TOTAL; - [ - { title: 'Max', expectedValue: expectedFreeMemory }, - { title: 'Average', expectedValue: expectedFreeMemory }, - ].map(({ title, expectedValue }) => - it(`returns correct ${title} value`, () => { - const memoryUsageMetric = metrics.charts.find((chart) => { - return chart.key === 'memory_usage_chart'; - }); - const series = memoryUsageMetric?.series.find((item) => item.title === title); - expect(series?.overallValue).to.eql(expectedValue); - const meanValue = meanBy( - series?.data.filter((item) => item.y !== null), - 'y' - ); - expect(meanValue).to.eql(expectedValue); - }) - ); - }); - - describe('Compute usage', () => { - const GBSeconds = 1024 * 1024 * 1024 * 1000; - const expectedValue = (MEMORY_TOTAL * BILLED_DURATION_MS) / GBSeconds; - let computeUsageMetric: typeof metrics['charts'][0] | undefined; - before(() => { - computeUsageMetric = metrics.charts.find((chart) => { - return chart.key === 'compute_usage'; - }); - }); - it('returns correct overall value', () => { - expect(computeUsageMetric?.series[0].overallValue).to.equal(expectedValue); - }); - - it('returns correct mean value', () => { - const meanValue = meanBy( - computeUsageMetric?.series[0]?.data.filter((item) => item.y !== 0), - 'y' - ); - expect(meanValue).to.equal(expectedValue); - }); - }); - - describe('Active instances', () => { - let activeInstancesMetric: typeof metrics['charts'][0] | undefined; - before(() => { - activeInstancesMetric = metrics.charts.find((chart) => { - return chart.key === 'active_instances'; - }); - }); - it('returns correct overall value', () => { - // there's only one node instance - expect(activeInstancesMetric?.series[0].overallValue).to.equal(1); - }); - - it('returns correct sum value', () => { - const sumValue = sumBy( - activeInstancesMetric?.series[0]?.data.filter((item) => item.y !== 0), - 'y' - ); - expect(sumValue).to.equal(numberOfTransactionsCreated); - }); - }); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/get_services.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/get_services.spec.ts new file mode 100644 index 0000000000000..7d036a7018de0 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/get_services.spec.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace'; +import expect from '@kbn/expect'; +import { IndexLifecyclePhaseSelectOption } from '@kbn/apm-plugin/common/storage_explorer_types'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const synthtraceEsClient = getService('synthtraceEsClient'); + const apmApiClient = getService('apmApiClient'); + + const start = '2021-01-01T12:00:00.000Z'; + const end = '2021-08-01T12:00:00.000Z'; + + // The terms enum API may return terms from deleted documents + // so we add a prefix to make sure we don't get data from other tests + const SERVICE_NAME_PREFIX = 'storage_explorer_services_'; + + async function getServices({ + environment = 'ENVIRONMENT_ALL', + kuery = '', + indexLifecyclePhase = IndexLifecyclePhaseSelectOption.All, + }: { + environment?: string; + kuery?: string; + indexLifecyclePhase?: IndexLifecyclePhaseSelectOption; + } = {}) { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/storage_explorer/get_services', + params: { + query: { + environment, + kuery, + indexLifecyclePhase, + }, + }, + }); + + return response.body.services + .filter((service) => service.serviceName.startsWith(SERVICE_NAME_PREFIX)) + .map((service) => ({ + ...service, + serviceName: service.serviceName.replace(SERVICE_NAME_PREFIX, ''), + })); + } + + registry.when('Get services', { config: 'basic', archives: [] }, () => { + before(async () => { + const serviceA = apm + .service({ name: `${SERVICE_NAME_PREFIX}a`, environment: 'production', agentName: 'java' }) + .instance('a'); + + const serviceB = apm + .service({ name: `${SERVICE_NAME_PREFIX}b`, environment: 'development', agentName: 'go' }) + .instance('b'); + + const serviceC = apm + .service({ name: `${SERVICE_NAME_PREFIX}c`, environment: 'development', agentName: 'go' }) + .instance('c'); + + const eventsWithinTimerange = timerange(new Date(start).getTime(), new Date(end).getTime()) + .interval('15m') + .rate(1) + .generator((timestamp) => [ + serviceA.transaction({ transactionName: 'GET /api' }).duration(1000).timestamp(timestamp), + serviceB.transaction({ transactionName: 'GET /api' }).duration(1000).timestamp(timestamp), + ]); + + const eventsOutsideOfTimerange = timerange( + new Date('2021-01-01T00:00:00.000Z').getTime(), + new Date(start).getTime() - 1 + ) + .interval('15m') + .rate(1) + .generator((timestamp) => + serviceC.transaction({ transactionName: 'GET /api' }).duration(1000).timestamp(timestamp) + ); + + await synthtraceEsClient.index(eventsWithinTimerange.merge(eventsOutsideOfTimerange)); + }); + + after(() => synthtraceEsClient.clean()); + + it('with no kuery, environment or index lifecycle phase set it returns services based on the terms enum API', async () => { + const items = await getServices(); + const serviceNames = items.map((item) => item.serviceName); + expect(serviceNames.sort()).to.eql(['a', 'b', 'c']); + }); + + it('with kuery set does it does not return any services', async () => { + const services = await getServices({ + kuery: 'service.name:*', + }); + expect(services).to.be.empty(); + }); + + it('with environment set to production it does not return any services', async () => { + const services = await getServices({ + environment: 'production', + }); + expect(services).to.be.empty(); + }); + + it('with index lifecycle phase set to hot it does not return any services', async () => { + const services = await getServices({ + indexLifecyclePhase: IndexLifecyclePhaseSelectOption.Hot, + }); + expect(services).to.be.empty(); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_details.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_details.spec.ts index a9ec2199c8b23..260c22eb68775 100644 --- a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_details.spec.ts +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_details.spec.ts @@ -36,7 +36,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { APIClientRequestParamsOf<'GET /internal/apm/services/{serviceName}/storage_details'>['params'] > ) { - return await apmApiClient.monitorIndicesUser({ + return await apmApiClient.monitorClusterAndIndicesUser({ endpoint: 'GET /internal/apm/services/{serviceName}/storage_details', params: { path: { @@ -70,8 +70,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when('Storage details', { config: 'basic', archives: [] }, () => { - describe('when data is loaded', () => { + // FLAKY: https://github.com/elastic/kibana/issues/144025 + registry.when.skip('Storage details', { config: 'basic', archives: [] }, () => { + describe.skip('when data is loaded', () => { before(async () => { const serviceGo = apm .service({ name: serviceName, environment: 'production', agentName: 'go' }) diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer.spec.ts index dc2429a5b8b3a..f54149665174b 100644 --- a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer.spec.ts +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer.spec.ts @@ -27,7 +27,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { APIClientRequestParamsOf<'GET /internal/apm/storage_explorer'>['params'] > ) { - return await apmApiClient.monitorIndicesUser({ + return await apmApiClient.monitorClusterAndIndicesUser({ endpoint: 'GET /internal/apm/storage_explorer', params: { query: { diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_privileges.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_privileges.spec.ts index 4d7cc8655840f..087bacdc898b3 100644 --- a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_privileges.spec.ts +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_privileges.spec.ts @@ -20,7 +20,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Storage explorer privileges', { config: 'basic', archives: [] }, () => { it('returns true when the user has the required indices privileges', async () => { - const { status, body } = await callApi(apmApiClient.monitorIndicesUser); + const { status, body } = await callApi(apmApiClient.monitorClusterAndIndicesUser); expect(status).to.be(200); expect(body.hasPrivileges).to.be(true); }); diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_summary_stats.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_summary_stats.spec.ts index afde7d243c227..37a747a3c3e76 100644 --- a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_summary_stats.spec.ts +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_summary_stats.spec.ts @@ -27,7 +27,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { APIClientRequestParamsOf<'GET /internal/apm/storage_explorer_summary_stats'>['params'] > ) { - return await apmApiClient.monitorIndicesUser({ + return await apmApiClient.monitorClusterAndIndicesUser({ endpoint: 'GET /internal/apm/storage_explorer_summary_stats', params: { query: { @@ -53,7 +53,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(status).to.be(200); expect(body.tracesPerMinute).to.be(0); expect(body.numberOfServices).to.be(0); - expect(body.estimatedSize).to.be(0); + expect(body.totalSize).to.be(0); + expect(body.estimatedIncrementalSize).to.be(0); + expect(body.diskSpaceUsedPct).to.be(0); expect(body.dailyDataGeneration).to.be(0); }); } @@ -100,7 +102,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(status).to.be(200); expect(body.numberOfServices).to.be(2); expect(roundNumber(body.tracesPerMinute)).to.be(2); - expect(body.estimatedSize).to.be.greaterThan(0); + expect(body.totalSize).to.be.greaterThan(0); + expect(body.estimatedIncrementalSize).to.be.greaterThan(0); + expect(body.diskSpaceUsedPct).to.be.greaterThan(0); expect(body.dailyDataGeneration).to.be.greaterThan(0); }); @@ -114,7 +118,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(status).to.be(200); expect(body.numberOfServices).to.be(1); expect(roundNumber(body.tracesPerMinute)).to.be(1); - expect(body.estimatedSize).to.be.greaterThan(0); + expect(body.totalSize).to.be.greaterThan(0); + expect(body.estimatedIncrementalSize).to.be.greaterThan(0); + expect(body.diskSpaceUsedPct).to.be.greaterThan(0); expect(body.dailyDataGeneration).to.be.greaterThan(0); }); @@ -128,7 +134,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(status).to.be(200); expect(body.tracesPerMinute).to.be(0); expect(body.numberOfServices).to.be(0); - expect(body.estimatedSize).to.be(0); + expect(body.totalSize).to.be.greaterThan(0); + expect(body.estimatedIncrementalSize).to.be(0); + expect(body.diskSpaceUsedPct).to.be.greaterThan(0); expect(body.dailyDataGeneration).to.be(0); }); @@ -142,7 +150,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(status).to.be(200); expect(body.numberOfServices).to.be(1); expect(roundNumber(body.tracesPerMinute)).to.be(1); - expect(body.estimatedSize).to.be.greaterThan(0); + expect(body.totalSize).to.be.greaterThan(0); + expect(body.estimatedIncrementalSize).to.be.greaterThan(0); + expect(body.diskSpaceUsedPct).to.be.greaterThan(0); expect(body.dailyDataGeneration).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_timeseries_chart.spec.ts b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_timeseries_chart.spec.ts index 632e17c37509a..f668b0ba71a5c 100644 --- a/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_timeseries_chart.spec.ts +++ b/x-pack/test/apm_api_integration/tests/storage_explorer/storage_explorer_timeseries_chart.spec.ts @@ -22,7 +22,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; async function callApi() { - return await apmApiClient.monitorIndicesUser({ + return await apmApiClient.monitorClusterAndIndicesUser({ endpoint: 'GET /internal/apm/storage_chart', params: { query: { diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 277bafb998761..b8703cd5a1380 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -348,7 +348,7 @@ export default function (providerContext: FtrProviderContext) { return 0; } - const policyId = 'package-policy-test-1'; + const policyId = 'package-policy-test-'; packagePoliciesToDeleteIds.push(policyId); const getPkRes = await supertest .get(`/api/fleet/epm/packages/system`) @@ -438,6 +438,92 @@ export default function (providerContext: FtrProviderContext) { expect(await getSystemPackagePolicyCopyVersion(copy3Id)).to.be(3); }); + it('should work with package policy with space in name', async () => { + const policyId = 'package-policy-test-1'; + packagePoliciesToDeleteIds.push(policyId); + const getPkRes = await supertest + .get(`/api/fleet/epm/packages/system`) + .set('kbn-xsrf', 'xxxx') + .expect(200); + systemPkgVersion = getPkRes.body.item.version; + // we must first force install the system package to override package verification error on policy create + const installPromise = supertest + .post(`/api/fleet/epm/packages/system-${systemPkgVersion}`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); + + await Promise.all([ + installPromise, + kibanaServer.savedObjects.create({ + id: policyId, + type: PACKAGE_POLICY_SAVED_OBJECT_TYPE, + overwrite: true, + attributes: { + name: `system-1`, + package: { + name: 'system', + }, + }, + }), + ]); + + const { + body: { + item: { id: originalPolicyId }, + }, + } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .query({ + sys_monitoring: false, + }) + .send({ + name: 'original policy with package policy with space in name', + namespace: 'default', + }) + .expect(200); + + await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Filetest with space in name', + description: '', + namespace: 'default', + policy_id: originalPolicyId, + enabled: true, + inputs: [], + package: { + name: 'filetest', + title: 'For File Tests', + version: '0.1.0', + }, + }) + .expect(200); + + const { + body: { + item: { id: copy1Id }, + }, + } = await supertest + .post(`/api/fleet/agent_policies/${originalPolicyId}/copy`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'copy 123', + description: 'Test', + }) + .expect(200); + + const { + body: { + item: { package_policies: packagePolicies }, + }, + } = await supertest.get(`/api/fleet/agent_policies/${copy1Id}`).expect(200); + + expect(packagePolicies[0].name).to.eql('Filetest with space in name (copy)'); + }); + it('should return a 404 with invalid source policy', async () => { await supertest .post(`/api/fleet/agent_policies/INVALID_POLICY_ID/copy`) diff --git a/x-pack/test/fleet_api_integration/apis/epm/index.js b/x-pack/test/fleet_api_integration/apis/epm/index.js index 137d7d59d8bfa..48af135f15ae2 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/index.js +++ b/x-pack/test/fleet_api_integration/apis/epm/index.js @@ -23,6 +23,7 @@ export default function loadTests({ loadTestFile }) { loadTestFile(require.resolve('./install_remove_kbn_assets_in_space')); loadTestFile(require.resolve('./install_remove_multiple')); loadTestFile(require.resolve('./install_update')); + loadTestFile(require.resolve('./install_tag_assets')); loadTestFile(require.resolve('./bulk_upgrade')); loadTestFile(require.resolve('./update_assets')); loadTestFile(require.resolve('./data_stream')); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_tag_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_tag_assets.ts new file mode 100644 index 0000000000000..7458912207a38 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/epm/install_tag_assets.ts @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; +import { skipIfNoDockerRegistry } from '../../helpers'; +import { setupFleetAndAgents } from '../agents/services'; +const testSpaceId = 'fleet_test_space'; + +export default function (providerContext: FtrProviderContext) { + const { getService } = providerContext; + const kibanaServer = getService('kibanaServer'); + const supertest = getService('supertest'); + const dockerServers = getService('dockerServers'); + const server = dockerServers.get('registry'); + const pkgName = 'only_dashboard'; + const pkgVersion = '0.1.0'; + + const uninstallPackage = async (pkg: string, version: string) => { + await supertest.delete(`/api/fleet/epm/packages/${pkg}/${version}`).set('kbn-xsrf', 'xxxx'); + }; + + const installPackageInSpace = async (pkg: string, version: string, spaceId: string) => { + await supertest + .post(`/s/${spaceId}/api/fleet/epm/packages/${pkg}/${version}`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); + }; + const createSpace = async (spaceId: string) => { + await supertest + .post(`/api/spaces/space`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: spaceId, + id: spaceId, + initials: 's', + color: '#D6BF57', + disabledFeatures: [], + imageUrl: '', + }) + .expect(200); + }; + + const getTag = async (id: string, space?: string) => + kibanaServer.savedObjects + .get({ + type: 'tag', + id, + ...(space && { space }), + }) + .catch(() => {}); + + const deleteTag = async (id: string) => + kibanaServer.savedObjects + .delete({ + type: 'tag', + id, + }) + .catch(() => {}); + + const deleteSpace = async (spaceId: string) => { + await supertest.delete(`/api/spaces/space/${spaceId}`).set('kbn-xsrf', 'xxxx').send(); + }; + describe('asset tagging', () => { + skipIfNoDockerRegistry(providerContext); + setupFleetAndAgents(providerContext); + before(async () => { + await createSpace(testSpaceId); + }); + + after(async () => { + await deleteSpace(testSpaceId); + }); + describe('creates correct tags when installing a package in non default space after installing in default space', async () => { + before(async () => { + if (!server.enabled) return; + await installPackageInSpace('all_assets', pkgVersion, 'default'); + await installPackageInSpace(pkgName, pkgVersion, testSpaceId); + }); + after(async () => { + if (!server.enabled) return; + await uninstallPackage('all_assets', pkgVersion); + await uninstallPackage(pkgName, pkgVersion); + }); + + it('Should create managed tag saved objects', async () => { + const defaultTag = await getTag('fleet-managed-default'); + expect(defaultTag).not.equal(undefined); + + const spaceTag = await getTag('fleet-managed-fleet_test_space', testSpaceId); + expect(spaceTag).not.equal(undefined); + }); + it('Should create package tag saved objects', async () => { + const defaultTag = await getTag(`fleet-pkg-all_assets-default`); + expect(defaultTag).not.equal(undefined); + + const spaceTag = await getTag(`fleet-pkg-${pkgName}-fleet_test_space`, testSpaceId); + expect(spaceTag).not.equal(undefined); + }); + }); + + describe('Handles presence of legacy tags', async () => { + before(async () => { + if (!server.enabled) return; + + // first clean up any existing tag saved objects as they arent cleaned on uninstall + await deleteTag('fleet-managed-default'); + await deleteTag(`fleet-pkg-${pkgName}-default`); + + // now create the legacy tags + await kibanaServer.savedObjects.create({ + type: 'tag', + id: 'managed', + overwrite: false, + attributes: { + name: 'managed', + description: '', + color: '#FFFFFF', + }, + }); + await kibanaServer.savedObjects.create({ + type: 'tag', + id: pkgName, + overwrite: false, + attributes: { + name: pkgName, + description: '', + color: '#FFFFFF', + }, + }); + + await installPackageInSpace(pkgName, pkgVersion, 'default'); + }); + after(async () => { + if (!server.enabled) return; + await uninstallPackage(pkgName, pkgVersion); + await deleteTag('managed'); + await deleteTag('tag'); + }); + + it('Should not create space aware tag saved objects if legacy tags exist', async () => { + const managedTag = await getTag('fleet-managed-default'); + expect(managedTag).equal(undefined); + + const pkgTag = await getTag(`fleet-pkg-${pkgName}-default`); + expect(pkgTag).equal(undefined); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts index c0b5197983aa4..8428d145c60ef 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts @@ -14,5 +14,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./timeseries')); loadTestFile(require.resolve('./dashboard')); loadTestFile(require.resolve('./top_n')); + loadTestFile(require.resolve('./table')); }); } diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts new file mode 100644 index 0000000000000..e3d52852cd61b --- /dev/null +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts @@ -0,0 +1,218 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { visualize, visualBuilder, lens, header } = getPageObjects([ + 'visualBuilder', + 'visualize', + 'header', + 'lens', + ]); + + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('Table', function describeIndexTests() { + before(async () => { + await visualize.initTests(); + }); + + beforeEach(async () => { + await visualBuilder.resetPage(); + await visualBuilder.clickTable(); + await header.waitUntilLoadingHasFinished(); + await visualBuilder.checkTableTabIsPresent(); + await visualBuilder.selectGroupByField('machine.os.raw'); + }); + + it('should not allow converting of not valid panel', async () => { + await visualBuilder.selectAggType('Max'); + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should not allow converting of unsupported aggregations', async () => { + await visualBuilder.selectAggType('Sum of Squares'); + await visualBuilder.setFieldForAggregation('machine.ram'); + + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should not allow converting sibling pipeline aggregations', async () => { + await visualBuilder.createNewAgg(); + + await visualBuilder.selectAggType('Overall Average', 1); + await visualBuilder.setFieldForAggregation('Count', 1); + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should not allow converting parent pipeline aggregations', async () => { + await visualBuilder.clickPanelOptions('table'); + await visualBuilder.setMetricsDataTimerangeMode('Last value'); + await visualBuilder.clickDataTab('table'); + await visualBuilder.createNewAgg(); + + await visualBuilder.selectAggType('Cumulative Sum', 1); + await visualBuilder.setFieldForAggregation('Count', 1); + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should not allow converting not valid aggregation function', async () => { + await visualBuilder.clickSeriesOption(); + await visualBuilder.setFieldForAggregateBy('clientip'); + await visualBuilder.setFunctionForAggregateFunction('Cumulative Sum'); + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should not allow converting series with different aggregation fucntion or aggregation by', async () => { + await visualBuilder.createNewAggSeries(); + await visualBuilder.selectAggType('Static Value', 1); + await visualBuilder.setStaticValue(10); + await visualBuilder.clickSeriesOption(); + await visualBuilder.setFieldForAggregateBy('bytes'); + await visualBuilder.setFunctionForAggregateFunction('Sum'); + await visualBuilder.clickSeriesOption(1); + await visualBuilder.setFieldForAggregateBy('bytes'); + await visualBuilder.setFunctionForAggregateFunction('Min'); + await header.waitUntilLoadingHasFinished(); + expect(await visualize.hasNavigateToLensButton()).to.be(false); + }); + + it('should allow converting a count aggregation', async () => { + expect(await visualize.hasNavigateToLensButton()).to.be(true); + }); + + it('should convert last value mode to reduced time range', async () => { + await visualBuilder.clickPanelOptions('table'); + await visualBuilder.setMetricsDataTimerangeMode('Last value'); + await visualBuilder.setIntervalValue('1m'); + await visualBuilder.clickDataTab('table'); + await header.waitUntilLoadingHasFinished(); + + await visualize.navigateToLensFromAnotherVisulization(); + await lens.waitForVisualization('lnsDataTable'); + await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); + await testSubjects.click('indexPattern-advanced-accordion'); + const reducedTimeRange = await testSubjects.find('indexPattern-dimension-reducedTimeRange'); + expect(await reducedTimeRange.getVisibleText()).to.be('1 minute (1m)'); + await retry.try(async () => { + const layerCount = await lens.getLayerCount(); + expect(layerCount).to.be(1); + const metricDimensionText = await lens.getDimensionTriggerText('lnsDatatable_metrics', 0); + expect(metricDimensionText).to.be('Count of records last 1m'); + }); + }); + + it('should convert static value to the metric dimension', async () => { + await visualBuilder.createNewAggSeries(); + await visualBuilder.selectAggType('Static Value', 1); + await visualBuilder.setStaticValue(10); + + await header.waitUntilLoadingHasFinished(); + + await visualize.navigateToLensFromAnotherVisulization(); + await lens.waitForVisualization('lnsDataTable'); + await retry.try(async () => { + const layerCount = await lens.getLayerCount(); + expect(layerCount).to.be(1); + const metricDimensionText1 = await lens.getDimensionTriggerText('lnsDatatable_metrics', 0); + const metricDimensionText2 = await lens.getDimensionTriggerText('lnsDatatable_metrics', 1); + expect(metricDimensionText1).to.be('Count of records'); + expect(metricDimensionText2).to.be('10'); + }); + }); + + it('should convert aggregate by to split row dimension', async () => { + await visualBuilder.clickSeriesOption(); + await visualBuilder.setFieldForAggregateBy('clientip'); + await visualBuilder.setFunctionForAggregateFunction('Sum'); + await header.waitUntilLoadingHasFinished(); + + await visualize.navigateToLensFromAnotherVisulization(); + await lens.waitForVisualization('lnsDataTable'); + await retry.try(async () => { + const layerCount = await lens.getLayerCount(); + expect(layerCount).to.be(1); + const splitRowsText1 = await lens.getDimensionTriggerText('lnsDatatable_rows', 0); + const splitRowsText2 = await lens.getDimensionTriggerText('lnsDatatable_rows', 1); + expect(splitRowsText1).to.be('Top 10 values of machine.os.raw'); + expect(splitRowsText2).to.be('Top 10 values of clientip'); + }); + + await lens.openDimensionEditor('lnsDatatable_rows > lns-dimensionTrigger', 0, 1); + const collapseBy = await testSubjects.find('indexPattern-collapse-by'); + expect(await collapseBy.getAttribute('value')).to.be('sum'); + }); + + it('should convert group by field with custom label', async () => { + await visualBuilder.setColumnLabelValue('test'); + await header.waitUntilLoadingHasFinished(); + + await visualize.navigateToLensFromAnotherVisulization(); + await lens.waitForVisualization('lnsDataTable'); + await retry.try(async () => { + const layerCount = await lens.getLayerCount(); + expect(layerCount).to.be(1); + const splitRowsText = await lens.getDimensionTriggerText('lnsDatatable_rows', 0); + expect(splitRowsText).to.be('test'); + }); + }); + + it('should convert color ranges', async () => { + await visualBuilder.clickSeriesOption(); + + await visualBuilder.setColorRuleOperator('>= greater than or equal'); + await visualBuilder.setColorRuleValue(10); + await visualBuilder.setColorPickerValue('#54B399'); + + await visualBuilder.createColorRule(1); + + await visualBuilder.setColorRuleOperator('>= greater than or equal'); + await visualBuilder.setColorRuleValue(100, 1); + await visualBuilder.setColorPickerValue('#54A000', 1); + + await header.waitUntilLoadingHasFinished(); + await visualize.navigateToLensFromAnotherVisulization(); + + await lens.waitForVisualization('lnsDataTable'); + await retry.try(async () => { + const closePalettePanels = await testSubjects.findAll( + 'lns-indexPattern-PalettePanelContainerBack' + ); + if (closePalettePanels.length) { + await lens.closePalettePanel(); + await lens.closeDimensionEditor(); + } + + await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); + + await lens.openPalettePanel('lnsDatatable'); + const colorStops = await lens.getPaletteColorStops(); + + expect(colorStops).to.eql([ + { stop: '10', color: 'rgba(84, 179, 153, 1)' }, + { stop: '100', color: 'rgba(84, 160, 0, 1)' }, + { stop: '', color: undefined }, + ]); + }); + }); + }); +} diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index 9eb23f62e06fe..c4b5a2831183c 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -54,7 +54,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const testHistoryIndex = '.kibana_task_manager_test_result'; - describe('scheduling and running tasks', () => { + // FLAKY: https://github.com/elastic/kibana/issues/141055 + describe.skip('scheduling and running tasks', () => { beforeEach(async () => { // clean up before each test return await supertest.delete('/api/sample_tasks').set('kbn-xsrf', 'xxx').expect(200); diff --git a/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts index c8ddb8aabec30..5539125d770a8 100644 --- a/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts +++ b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts @@ -18,7 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('filebeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await retry.try(async () => { - const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); + const hitCount = await PageObjects.discover.getHitCountInt(); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts index f6a8aa7875302..50b254a65559e 100644 --- a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('metricbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); + const hitCount = await PageObjects.discover.getHitCountInt(); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts index e4bf8288a2093..367f7a34f7003 100644 --- a/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts +++ b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts @@ -32,7 +32,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('packetbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); + const hitCount = await PageObjects.discover.getHitCountInt(); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts index 4f8107f937a77..99bcf4e15dcd6 100644 --- a/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts +++ b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('winlogbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); + const hitCount = await PageObjects.discover.getHitCountInt(); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/upgrade/apps/discover/discover_smoke_tests.ts b/x-pack/test/upgrade/apps/discover/discover_smoke_tests.ts index bfb51f3e5336d..64adb488ca2b9 100644 --- a/x-pack/test/upgrade/apps/discover/discover_smoke_tests.ts +++ b/x-pack/test/upgrade/apps/discover/discover_smoke_tests.ts @@ -40,12 +40,12 @@ export default function ({ getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern(String(index)); await PageObjects.discover.waitUntilSearchingHasFinished(); if (timefield) { - await PageObjects.timePicker.setCommonlyUsedTime('Last_24 hours'); + await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await PageObjects.discover.waitUntilSearchingHasFinished(); } }); it('shows hit count greater than zero', async () => { - const hitCount = await PageObjects.discover.getHitCount(); + const hitCount = await PageObjects.discover.getHitCountInt(); if (hits === '') { expect(hitCount).to.be.greaterThan(0); } else { @@ -69,12 +69,12 @@ export default function ({ getPageObjects }: FtrProviderContext) { await PageObjects.home.launchSampleDiscover(name); await PageObjects.header.waitUntilLoadingHasFinished(); if (timefield) { - await PageObjects.timePicker.setCommonlyUsedTime('Last_24 hours'); + await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await PageObjects.discover.waitUntilSearchingHasFinished(); } }); it('shows hit count greater than zero', async () => { - const hitCount = await PageObjects.discover.getHitCount(); + const hitCount = await PageObjects.discover.getHitCountInt(); if (hits === '') { expect(hitCount).to.be.greaterThan(0); } else { diff --git a/yarn.lock b/yarn.lock index 1770a163d752c..9ed18bf2180b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/css-tools@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd" + integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g== + "@ampproject/remapping@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" @@ -108,7 +113,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.19.6", "@babel/core@^7.7.5": +"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.19.6", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": version "7.19.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.6.tgz#7122ae4f5c5a37c0946c066149abd8e75f81540f" integrity sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg== @@ -145,7 +150,7 @@ dependencies: eslint-rule-composer "^0.3.0" -"@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.19.6": +"@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.19.6", "@babel/generator@^7.7.2": version "7.19.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.6.tgz#9e481a3fe9ca6261c972645ae3904ec0f9b34a1d" integrity sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA== @@ -713,7 +718,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.18.6": +"@babel/plugin-syntax-typescript@^7.18.6", "@babel/plugin-syntax-typescript@^7.7.2": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== @@ -1191,7 +1196,7 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.3", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.18.9", "@babel/traverse@^7.19.4", "@babel/traverse@^7.19.6", "@babel/traverse@^7.4.5": +"@babel/traverse@^7.10.3", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.18.9", "@babel/traverse@^7.19.4", "@babel/traverse@^7.19.6", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.2": version "7.19.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.6.tgz#7b4c865611df6d99cb131eec2e8ac71656a490dc" integrity sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ== @@ -2348,61 +2353,61 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^27.5.1" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" + jest-message-util "^27.5.1" + jest-util "^27.5.1" slash "^3.0.0" -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" +"@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" + emittery "^0.8.1" exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" - jest-mock "^26.6.2" + jest-mock "^27.5.1" "@jest/expect-utils@^28.1.1": version "28.1.1" @@ -2411,58 +2416,57 @@ dependencies: jest-get-type "^28.0.2" -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" + istanbul-lib-instrument "^5.1.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" + v8-to-istanbul "^8.1.0" "@jest/schemas@^28.0.2": version "28.0.2" @@ -2471,35 +2475,34 @@ dependencies: "@sinclair/typebox" "^0.23.3" -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== dependencies: callsites "^3.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" source-map "^0.6.0" -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" "@jest/transform@^26.6.2": version "26.6.2" @@ -2522,7 +2525,28 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^26", "@jest/types@^26.6.2": +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== @@ -2533,10 +2557,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jest/types@^27.1.1": - version "27.1.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" - integrity sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA== +"@jest/types@^27", "@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" @@ -3093,6 +3117,18 @@ version "0.0.0" uid "" +"@kbn/core-lifecycle-server-internal@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-internal": + version "0.0.0" + uid "" + +"@kbn/core-lifecycle-server-mocks@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-mocks": + version "0.0.0" + uid "" + +"@kbn/core-lifecycle-server@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server": + version "0.0.0" + uid "" + "@kbn/core-logging-server-internal@link:bazel-bin/packages/core/logging/core-logging-server-internal": version "0.0.0" uid "" @@ -3185,6 +3221,18 @@ version "0.0.0" uid "" +"@kbn/core-plugins-server-internal@link:bazel-bin/packages/core/plugins/core-plugins-server-internal": + version "0.0.0" + uid "" + +"@kbn/core-plugins-server-mocks@link:bazel-bin/packages/core/plugins/core-plugins-server-mocks": + version "0.0.0" + uid "" + +"@kbn/core-plugins-server@link:bazel-bin/packages/core/plugins/core-plugins-server": + version "0.0.0" + uid "" + "@kbn/core-preboot-server-internal@link:bazel-bin/packages/core/preboot/core-preboot-server-internal": version "0.0.0" uid "" @@ -4868,10 +4916,10 @@ dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== dependencies: "@sinonjs/commons" "^1.7.0" @@ -5853,10 +5901,10 @@ resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.3.tgz#fbb68696899d7b8c1b9b891eded9c04fe2cd5529" integrity sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A== -"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.12.0": - version "8.12.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.12.0.tgz#fef5e545533fb084175dda6509ee71d7d2f72e23" - integrity sha512-rBrJk5WjI02X1edtiUcZhgyhgBhiut96r5Jp8J5qktKdcvLcZpKDW8i2hkGMMItxrghjXuQ5AM6aE0imnFawaw== +"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.17.1": + version "8.17.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.17.1.tgz#2d7af4ff6dad8d837630fecd08835aee08320ad7" + integrity sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" @@ -5867,30 +5915,27 @@ lz-string "^1.4.4" pretty-format "^27.0.2" -"@testing-library/jest-dom@^5.16.3": - version "5.16.3" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.3.tgz#b76851a909586113c20486f1679ffb4d8ec27bfa" - integrity sha512-u5DfKj4wfSt6akfndfu1eG06jsdyA/IUrlX2n3pyq5UXgXMhXY+NJb8eNK/7pqPWAhCKsCGWDdDO0zKMKAYkEA== +"@testing-library/jest-dom@^5.16.5": + version "5.16.5" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e" + integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA== dependencies: + "@adobe/css-tools" "^4.0.1" "@babel/runtime" "^7.9.2" "@types/testing-library__jest-dom" "^5.9.1" aria-query "^5.0.0" chalk "^3.0.0" - css "^3.0.0" css.escape "^1.5.1" dom-accessibility-api "^0.5.6" lodash "^4.17.15" redent "^3.0.0" -"@testing-library/react-hooks@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-7.0.2.tgz#3388d07f562d91e7f2431a4a21b5186062ecfee0" - integrity sha512-dYxpz8u9m4q1TuzfcUApqi8iFfR6R0FaMbr2hjZJy1uC8z+bO/K4v8Gs9eogGKYQop7QsrBTFkv/BCF7MzD2Cg== +"@testing-library/react-hooks@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12" + integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g== dependencies: "@babel/runtime" "^7.12.5" - "@types/react" ">=16.9.0" - "@types/react-dom" ">=16.9.0" - "@types/react-test-renderer" ">=16.9.0" react-error-boundary "^3.1.0" "@testing-library/react@^12.1.5": @@ -5914,6 +5959,11 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -6127,7 +6177,7 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== -"@types/babel__core@*", "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.19", "@types/babel__core@^7.1.7": +"@types/babel__core@*", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.19": version "7.1.19" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== @@ -6138,7 +6188,25 @@ "@types/babel__template" "*" "@types/babel__traverse" "*" -"@types/babel__generator@*", "@types/babel__generator@^7.6.4": +"@types/babel__core@^7.0.0": + version "7.1.10" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.10.tgz#ca58fc195dd9734e77e57c6f2df565623636ab40" + integrity sha512-x8OM8XzITIMyiwl5Vmo2B1cR1S1Ipkyv4mdlbJjMa1lmuKvKY9FrBbEANIaMlnWn5Rf7uO+rC/VgYabNkE17Hw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.0.2.tgz#d2112a6b21fad600d7674274293c85dce0cb47fc" + integrity sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__generator@^7.6.4": version "7.6.4" resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== @@ -6649,13 +6717,6 @@ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a" integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A== -"@types/http-proxy-agent@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/http-proxy-agent/-/http-proxy-agent-2.0.2.tgz#942c1f35c7e1f0edd1b6ffae5d0f9051cfb32be1" - integrity sha512-2S6IuBRhqUnH1/AUx9k8KWtY3Esg4eqri946MnxTG5HwehF1S5mqLln8fcyMiuQkY72p2gH3W+rIPqp5li0LyQ== - dependencies: - "@types/node" "*" - "@types/http-proxy@^1.17.4", "@types/http-proxy@^1.17.8": version "1.17.9" resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" @@ -6715,7 +6776,7 @@ dependencies: "@types/jest" "*" -"@types/jest@*", "@types/jest@^26.0.16", "@types/jest@^26.0.22": +"@types/jest@*", "@types/jest@^26.0.16": version "26.0.22" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6" integrity sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw== @@ -6723,6 +6784,14 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" +"@types/jest@^27.4.1": + version "27.5.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" + integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + "@types/joi@^17.2.3": version "17.2.3" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-17.2.3.tgz#b7768ed9d84f1ebd393328b9f97c1cf3d2b94798" @@ -7281,6 +7350,18 @@ version "0.0.0" uid "" +"@types/kbn__core-lifecycle-server-internal@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-lifecycle-server-mocks@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-lifecycle-server@link:bazel-bin/packages/core/lifecycle/core-lifecycle-server/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-logging-server-internal@link:bazel-bin/packages/core/logging/core-logging-server-internal/npm_module_types": version "0.0.0" uid "" @@ -7373,6 +7454,18 @@ version "0.0.0" uid "" +"@types/kbn__core-plugins-server-internal@link:bazel-bin/packages/core/plugins/core-plugins-server-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-plugins-server-mocks@link:bazel-bin/packages/core/plugins/core-plugins-server-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-plugins-server@link:bazel-bin/packages/core/plugins/core-plugins-server/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-preboot-server-internal@link:bazel-bin/packages/core/preboot/core-preboot-server-internal/npm_module_types": version "0.0.0" uid "" @@ -8451,7 +8544,7 @@ dependencies: "@types/node" "*" -"@types/prettier@^2.0.0", "@types/prettier@^2.3.2": +"@types/prettier@^2.0.0", "@types/prettier@^2.1.5", "@types/prettier@^2.3.2": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== @@ -8515,7 +8608,7 @@ dependencies: "@types/react" "*" -"@types/react-dom@<18.0.0", "@types/react-dom@>=16.9.0", "@types/react-dom@^17.0.17": +"@types/react-dom@<18.0.0", "@types/react-dom@^17.0.17": version "17.0.17" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== @@ -8606,7 +8699,7 @@ dependencies: "@types/react" "*" -"@types/react-test-renderer@>=16.9.0", "@types/react-test-renderer@^17.0.2": +"@types/react-test-renderer@^17.0.2": version "17.0.2" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz#5f800a39b12ac8d2a2149e7e1885215bcf4edbbf" integrity sha512-+F1KONQTBHDBBhbHuT2GNydeMpPuviduXIVJRB7Y4nma4NR5DrTJfMMZ+jbhEHbpwL+Uqhs1WXh4KHiyrtYTPg== @@ -8649,7 +8742,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17", "@types/react@^17.0.45": +"@types/react@*", "@types/react@^17", "@types/react@^17.0.45": version "17.0.45" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.45.tgz#9b3d5b661fd26365fefef0e766a1c6c30ccf7b3f" integrity sha512-YfhQ22Lah2e3CHPsb93tRwIGNiSwkuz1/blk4e6QrWS0jQzCSNbGLtOEYhPg02W0yGTTmpajp7dCTbBAMN3qsg== @@ -9559,7 +9652,7 @@ JSONStream@1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.3, abab@^2.0.4: +abab@^2.0.3, abab@^2.0.4, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== @@ -9636,7 +9729,7 @@ acorn@^7.0.0, acorn@^7.1.1, acorn@^7.4.0, acorn@^7.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1: +acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== @@ -9656,13 +9749,6 @@ after-all-results@^2.0.0: resolved "https://registry.yarnpkg.com/after-all-results/-/after-all-results-2.0.0.tgz#6ac2fc202b500f88da8f4f5530cfa100f4c6a2d0" integrity sha1-asL8ICtQD4jaj09VMM+hAPTGotA= -agent-base@4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -10338,7 +10424,7 @@ atob-lite@^2.0.0: resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= -atob@^2.1.1, atob@^2.1.2: +atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== @@ -10451,18 +10537,18 @@ axobject-query@^2.2.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== - dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" +babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" slash "^3.0.0" babel-loader@^8.0.0, babel-loader@^8.2.5: @@ -10534,10 +10620,10 @@ babel-plugin-istanbul@^6.0.0, babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -10656,12 +10742,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== dependencies: - babel-plugin-jest-hoist "^26.6.2" + babel-plugin-jest-hoist "^27.5.1" babel-preset-current-node-syntax "^1.0.0" babel-runtime@6.x, babel-runtime@^6.26.0: @@ -11622,10 +11708,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== clamp@^1.0.1: version "1.0.1" @@ -12573,15 +12659,6 @@ css@2.X, css@^2.2.1, css@^2.2.4: source-map-resolve "^0.5.2" urix "^0.1.0" -css@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" - integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== - dependencies: - inherits "^2.0.4" - source-map "^0.6.1" - source-map-resolve "^0.6.0" - csscolorparser@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b" @@ -12663,7 +12740,7 @@ cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.2.0: +cssstyle@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== @@ -13288,7 +13365,7 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -decimal.js@^10.2.0: +decimal.js@^10.2.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== @@ -14074,10 +14151,10 @@ email-addresses@^5.0.0: resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-5.0.0.tgz#7ae9e7f58eef7d5e3e2c2c2d3ea49b78dc854fa6" integrity sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw== -emittery@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451" - integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ== +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== "emoji-regex@>=6.0.0 <=6.1.1": version "6.1.1" @@ -14204,13 +14281,13 @@ enzyme-shallow-equal@^1.0.0, enzyme-shallow-equal@^1.0.1: has "^1.0.3" object-is "^1.1.2" -enzyme-to-json@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.6.1.tgz#d60740950bc7ca6384dfe6fe405494ec5df996bc" - integrity sha512-15tXuONeq5ORoZjV/bUo2gbtZrN2IH+Z6DvL35QmZyKHgbY1ahn6wcnLd9Xv9OjiwbAXiiP8MRZwbZrCv1wYNg== +enzyme-to-json@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.6.2.tgz#94f85c413bcae8ab67be53b0a94b69a560e27823" + integrity sha512-Ynm6Z6R6iwQ0g2g1YToz6DWhxVnt8Dy1ijR2zynRKxTyBGA8rCDXU3rs2Qc4OKvUvc2Qoe1bcFK6bnPs20TrTg== dependencies: "@types/cheerio" "^0.22.22" - lodash "^4.17.15" + lodash "^4.17.21" react-is "^16.12.0" enzyme@^3.11.0: @@ -14377,18 +14454,11 @@ es6-map@^0.1.5: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@^4.0.3, es6-promise@^4.2.8: +es6-promise@^4.2.8: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - es6-set@^0.1.5, es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -14453,7 +14523,7 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.11.1, escodegen@^1.14.1: +escodegen@^1.11.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -14890,7 +14960,7 @@ exec-sh@^0.3.2: resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" integrity sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg== -execa@4.1.0, execa@^4.0.0, execa@^4.0.2: +execa@4.1.0, execa@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -14992,17 +15062,15 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" -expect@^27.0.2: - version "27.2.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.0.tgz#40eb89a492afb726a3929ccf3611ee0799ab976f" - integrity sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ== +expect@^27.0.2, expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== dependencies: - "@jest/types" "^27.1.1" - ansi-styles "^5.0.0" - jest-get-type "^27.0.6" - jest-matcher-utils "^27.2.0" - jest-message-util "^27.2.0" - jest-regex-util "^27.0.6" + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" expect@^28.1.1: version "28.1.1" @@ -15612,6 +15680,15 @@ form-data@^2.3.1, form-data@^2.3.3: combined-stream "^1.0.6" mime-types "^2.1.12" +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -15791,7 +15868,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2, fsevents@~2.3.2: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -16358,11 +16435,6 @@ graphql@^16.6.0: resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb" integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw== -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - gulp-brotli@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/gulp-brotli/-/gulp-brotli-3.0.0.tgz#7f5a1d8a6d43cab28056f9e56f29ae071dcfe4b4" @@ -16962,14 +17034,6 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" @@ -16979,6 +17043,15 @@ http-proxy-agent@^4.0.1: agent-base "6" debug "4" +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + http-proxy-middleware@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" @@ -17807,7 +17880,7 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-potential-custom-element-name@^1.0.0: +is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== @@ -18071,7 +18144,7 @@ istanbul-lib-hook@^3.0.0: dependencies: append-transform "^2.0.0" -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: +istanbul-lib-instrument@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -18081,7 +18154,7 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" -istanbul-lib-instrument@^5.0.4: +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== @@ -18123,10 +18196,10 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== +istanbul-reports@^3.0.2, istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -18169,92 +18242,95 @@ jest-axe@^5.0.0: jest-matcher-utils "27.0.2" lodash.merge "4.6.2" -jest-canvas-mock@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.3.1.tgz#9535d14bc18ccf1493be36ac37dd349928387826" - integrity sha512-5FnSZPrX3Q2ZfsbYNE3wqKR3+XorN8qFzDzB5o0golWgt6EOX1+emBnpOc9IAQ+NXFj8Nzm3h7ZdE/9H0ylBcg== +jest-canvas-mock@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.4.0.tgz#947b71442d7719f8e055decaecdb334809465341" + integrity sha512-mmMpZzpmLzn5vepIaHk5HoH3Ka4WykbSoLuG/EKoJd0x0ID/t+INo1l8ByfcUJuDM+RIsL4QDg/gDnBbrj2/IQ== dependencies: cssfontparser "^1.2.1" moo-color "^1.0.2" -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" -jest-circus@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-26.6.3.tgz#3cc7ef2a6a3787e5d7bfbe2c72d83262154053e7" - integrity sha512-ACrpWZGcQMpbv13XbzRzpytEJlilP/Su0JtNCi5r/xLpOUhnaIJr8leYYpLEMgPFURZISEHrnnpmB54Q/UziPw== +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" - expect "^26.6.2" + expect "^27.5.1" is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - stack-utils "^2.0.2" - throat "^5.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== +jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" chalk "^4.0.0" exit "^0.1.2" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" prompts "^2.0.1" - yargs "^15.4.1" + yargs "^16.2.0" -jest-config@^26, jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" chalk "^4.0.0" + ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" jest-diff@^26.0.0, jest-diff@^26.6.2: version "26.6.2" @@ -18266,7 +18342,7 @@ jest-diff@^26.0.0, jest-diff@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-diff@^27.0.2, jest-diff@^27.2.0: +jest-diff@^27.0.2, jest-diff@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== @@ -18286,55 +18362,55 @@ jest-diff@^28.1.1: jest-get-type "^28.0.2" pretty-format "^28.1.1" -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== dependencies: detect-newline "^3.0.0" -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^27.5.1" chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-mock "^27.5.1" + jest-util "^27.5.1" jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-get-type@^27.0.1, jest-get-type@^27.0.6, jest-get-type@^27.5.1: +jest-get-type@^27.0.1, jest-get-type@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== @@ -18365,37 +18441,56 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^26.6.2" + expect "^27.5.1" is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" jest-matcher-utils@27.0.2: version "27.0.2" @@ -18417,15 +18512,15 @@ jest-matcher-utils@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-matcher-utils@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz#b4d224ab88655d5fab64b96b989ac349e2f5da43" - integrity sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw== +jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== dependencies: chalk "^4.0.0" - jest-diff "^27.2.0" - jest-get-type "^27.0.6" - pretty-format "^27.2.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" jest-matcher-utils@^28.1.1: version "28.1.1" @@ -18452,18 +18547,18 @@ jest-message-util@^26.6.2: slash "^3.0.0" stack-utils "^2.0.2" -jest-message-util@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.2.0.tgz#2f65c71df55267208686b1d7514e18106c91ceaf" - integrity sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w== +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.1.1" + "@jest/types" "^27.5.1" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^27.2.0" + pretty-format "^27.5.1" slash "^3.0.0" stack-utils "^2.0.3" @@ -18482,12 +18577,12 @@ jest-message-util@^28.1.1: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^27.5.1" "@types/node" "*" jest-pnp-resolver@^1.2.2: @@ -18505,19 +18600,19 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-regex-util@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" - integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" jest-resolve@^26.6.2: version "26.6.2" @@ -18533,64 +18628,76 @@ jest-resolve@^26.6.2: resolve "^1.18.1" slash "^3.0.0" -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== +jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26, jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" chalk "^4.0.0" - cjs-module-lexer "^0.6.0" + cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - exit "^0.1.2" + execa "^5.0.0" glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.4.1" jest-serializer@^26.6.2: version "26.6.2" @@ -18600,6 +18707,14 @@ jest-serializer@^26.6.2: "@types/node" "*" graceful-fs "^4.2.4" +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + jest-silent-reporter@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jest-silent-reporter/-/jest-silent-reporter-0.5.0.tgz#5fd8ccd61665227e3bf19d908b7350719d06ff38" @@ -18608,7 +18723,7 @@ jest-silent-reporter@^0.5.0: chalk "^4.0.0" jest-util "^26.0.0" -jest-snapshot@^26.3.0, jest-snapshot@^26.6.2: +jest-snapshot@^26.3.0: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== @@ -18630,6 +18745,34 @@ jest-snapshot@^26.3.0, jest-snapshot@^26.6.2: pretty-format "^26.6.2" semver "^7.3.2" +jest-snapshot@^27.0.2, jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + jest-specific-snapshot@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jest-specific-snapshot/-/jest-specific-snapshot-4.0.0.tgz#a52a2e223e7576e610dbeaf341207c557ac20554" @@ -18637,7 +18780,14 @@ jest-specific-snapshot@^4.0.0: dependencies: jest-snapshot "^26.3.0" -jest-styled-components@^7.0.3: +jest-specific-snapshot@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/jest-specific-snapshot/-/jest-specific-snapshot-5.0.0.tgz#48f72d5613af7f3e30df75b6b3534db6bab32ea0" + integrity sha512-V65vuPxZQExD3tGbv+Du5tbG1E3H3Dq/HFbsCEkPJP27w5vr/nATQJl61Dx5doBfu54OrJak0JaeYVSeZubDKg== + dependencies: + jest-snapshot "^27.0.2" + +jest-styled-components@7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-7.0.3.tgz#cc0b031f910484e68f175568682f3969ff774b2c" integrity sha512-jj9sWyshehUnB0P9WFUaq9Bkh6RKYO8aD8lf3gUrXRwg/MRddTFk7U9D9pC4IAI3v9fbz4vmrMxwaecTpG8NKA== @@ -18656,6 +18806,18 @@ jest-util@^26.0.0, jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-util@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.1.tgz#ff39e436a1aca397c0ab998db5a51ae2b7080d05" @@ -18668,29 +18830,29 @@ jest-util@^28.1.1: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== dependencies: - "@jest/types" "^26.6.2" - camelcase "^6.0.0" + "@jest/types" "^27.5.1" + camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^26.3.0" + jest-get-type "^27.5.1" leven "^3.1.0" - pretty-format "^26.6.2" + pretty-format "^27.5.1" -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.6.2" + jest-util "^27.5.1" string-length "^4.0.1" jest-worker@^26.5.0, jest-worker@^26.6.2: @@ -18702,7 +18864,7 @@ jest-worker@^26.5.0, jest-worker@^26.6.2: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.4.5: +jest-worker@^27.4.5, jest-worker@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -18711,14 +18873,14 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== +jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== dependencies: - "@jest/core" "^26.6.3" + "@jest/core" "^27.5.1" import-local "^3.0.2" - jest-cli "^26.6.3" + jest-cli "^27.5.1" joi@*, joi@^17.3.0, joi@^17.4.0: version "17.4.0" @@ -18817,36 +18979,37 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdom@^16.4.0: - version "16.4.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" - integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== +jsdom@^16.4.0, jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== dependencies: - abab "^2.0.3" - acorn "^7.1.1" + abab "^2.0.5" + acorn "^8.2.4" acorn-globals "^6.0.0" cssom "^0.4.4" - cssstyle "^2.2.0" + cssstyle "^2.3.0" data-urls "^2.0.0" - decimal.js "^10.2.0" + decimal.js "^10.2.1" domexception "^2.0.1" - escodegen "^1.14.1" + escodegen "^2.0.0" + form-data "^3.0.0" html-encoding-sniffer "^2.0.1" - is-potential-custom-element-name "^1.0.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" nwsapi "^2.2.0" - parse5 "5.1.1" - request "^2.88.2" - request-promise-native "^1.0.8" - saxes "^5.0.0" + parse5 "6.0.1" + saxes "^5.0.1" symbol-tree "^3.2.4" - tough-cookie "^3.0.1" + tough-cookie "^4.0.0" w3c-hr-time "^1.0.2" w3c-xmlserializer "^2.0.0" webidl-conversions "^6.1.0" whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - ws "^7.2.3" + whatwg-url "^8.5.0" + ws "^7.4.6" xml-name-validator "^3.0.0" jsesc@^2.5.1: @@ -21092,18 +21255,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-notifier@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1" - integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -21737,11 +21888,6 @@ p-cancelable@^2.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e" integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg== -p-each-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" - integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== - p-event@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.1.0.tgz#e92bb866d7e8e5b732293b1c8269d38e9982bf8e" @@ -21971,7 +22117,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -21998,12 +22144,7 @@ parse5-htmlparser2-tree-adapter@^6.0.1: dependencies: parse5 "^6.0.1" -parse5@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.0, parse5@^6.0.1: +parse5@6.0.1, parse5@^6.0.0, parse5@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== @@ -22236,7 +22377,7 @@ pino@^6.11.2: quick-format-unescaped "^4.0.3" sonic-boom "^1.0.2" -pirates@^4.0.1, pirates@^4.0.5: +pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -22834,7 +22975,7 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^27.0.2, pretty-format@^27.2.0, pretty-format@^27.5.1: +pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== @@ -23552,10 +23693,10 @@ react-grid-layout@^1.3.4: react-draggable "^4.0.0" react-resizable "^3.0.4" -react-hook-form@^7.37.0: - version "7.37.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.37.0.tgz#4d1738f092d3d8a3ade34ee892d97350b1032b19" - integrity sha512-6NFTxsnw+EXSpNNvLr5nFMjPdYKRryQcelTHg7zwBB6vAzfPIcZq4AExP4heVlwdzntepQgwiOQW4z7Mr99Lsg== +react-hook-form@^7.38.0: + version "7.38.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.38.0.tgz#53d6a68df587ce4ce88352f63e0ecc7fc8779320" + integrity sha512-gxWW1kMeru9xR1GoR+Iw4hA+JBOM3SHfr4DWCUKY0xc7Vv1MLsF109oHtBeWl9shcyPFx67KHru44DheN0XY5A== react-input-autosize@^3.0.0: version "3.0.0" @@ -24582,23 +24723,7 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.8: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.44.0, request@^2.88.0, request@^2.88.2: +request@^2.44.0, request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -24714,6 +24839,11 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -25043,7 +25173,7 @@ sax@>=0.6.0, sax@^1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.0: +saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== @@ -25400,11 +25530,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - side-channel@^1.0.2, side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -25665,14 +25790,6 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" -source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - source-map-support@0.5.9: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" @@ -26016,11 +26133,6 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - store2@^2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" @@ -26783,10 +26895,10 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== throttle-debounce@^2.1.0: version "2.1.0" @@ -27060,24 +27172,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== - dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" - punycode "^2.1.1" - -tough-cookie@^4.1.2: +tough-cookie@^4.0.0, tough-cookie@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== @@ -27087,6 +27182,14 @@ tough-cookie@^4.1.2: universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" @@ -27963,10 +28066,10 @@ v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz#b4fe00e35649ef7785a9b7fcebcea05f37c332fc" - integrity sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA== +v8-to-istanbul@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -28847,7 +28950,7 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -whatwg-url@^8.0.0: +whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== @@ -29079,7 +29182,7 @@ ws@8.9.0, ws@>=8.7.0, ws@^8.2.3, ws@^8.4.2: resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg== -ws@^7.2.3, ws@^7.3.1, ws@^7.4.6: +ws@^7.3.1, ws@^7.4.6: version "7.5.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== @@ -29174,10 +29277,10 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm@^4.18.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.18.0.tgz#a1f6ab2c330c3918fb094ae5f4c2562987398ea1" - integrity sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ== +xterm@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0.tgz#0af50509b33d0dc62fde7a4ec17750b8e453cc5c" + integrity sha512-tmVsKzZovAYNDIaUinfz+VDclraQpPUnAME+JawosgWRMphInDded/PuY0xmU5dOhyeYZsI0nz5yd8dPYsdLTA== y18n@^3.2.0: version "3.2.2"