diff --git a/.buildkite/ftr_oblt_serverless_configs.yml b/.buildkite/ftr_oblt_serverless_configs.yml index f583f1bd2adce..737add5ebccf6 100644 --- a/.buildkite/ftr_oblt_serverless_configs.yml +++ b/.buildkite/ftr_oblt_serverless_configs.yml @@ -27,6 +27,7 @@ enabled: - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group7.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group8.ts - x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts + - x-pack/test_serverless/functional/test_suites/observability/config.telemetry.ts # serverless config files that run deployment-agnostic tests - x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts - x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.apm.serverless.config.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index f55fc2f7b4898..c1236a04685fb 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -64,7 +64,6 @@ enabled: - test/functional/apps/dashboard/group5/config.ts - test/functional/apps/dashboard/group6/config.ts - test/functional/apps/discover/ccs_compatibility/config.ts - - test/functional/apps/discover/classic/config.ts - test/functional/apps/discover/embeddable/config.ts - test/functional/apps/discover/esql/config.ts - test/functional/apps/discover/group1/config.ts @@ -231,6 +230,7 @@ enabled: - x-pack/test/functional/apps/lens/group4/config.ts - x-pack/test/functional/apps/lens/group5/config.ts - x-pack/test/functional/apps/lens/group6/config.ts + - x-pack/test/functional/apps/lens/group7/config.ts - x-pack/test/functional/apps/lens/open_in_lens/tsvb/config.ts - x-pack/test/functional/apps/lens/open_in_lens/agg_based/config.ts - x-pack/test/functional/apps/lens/open_in_lens/dashboard/config.ts diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index 69d4801292cf7..74d82d40c8bce 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -19,6 +19,9 @@ disabled: - x-pack/test_serverless/functional/config.base.ts - x-pack/test_serverless/shared/config.base.ts + # MKI only configs files + - x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts + defaultQueue: 'n2-4-spot' enabled: - x-pack/test_serverless/api_integration/test_suites/security/config.ts @@ -32,7 +35,6 @@ enabled: - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts - - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts - x-pack/test_serverless/functional/test_suites/security/config.saved_objects_management.ts - x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts @@ -74,7 +76,8 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/large_prebuilt_rules_package/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/update_prebuilt_rules_package/trial_license_complete_tier/configs/serverless.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/customization_enabled/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/customization_disabled/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_delete/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_delete/basic_license_essentials_tier/configs/serverless.config.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index f7caacba05e1b..bd8bc9e922f0d 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -58,7 +58,8 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/large_prebuilt_rules_package/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/update_prebuilt_rules_package/trial_license_complete_tier/configs/ess.config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/customization_enabled/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/prebuilt_rule_customization/customization_disabled/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_delete/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_delete/basic_license_essentials_tier/configs/ess.config.ts @@ -100,3 +101,4 @@ enabled: - x-pack/test/cloud_security_posture_functional/config.ts - x-pack/test/cloud_security_posture_functional/config.agentless.ts - x-pack/test/cloud_security_posture_functional/data_views/config.ts + - x-pack/test/automatic_import_api_integration/security/config_basic.ts diff --git a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml index bedb81cccc5a4..f651a8c9e4f96 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml @@ -3,7 +3,7 @@ apiVersion: backstage.io/v1alpha1 kind: Resource metadata: name: bk-kibana-fips-daily - description: Run Kibana FIPS smoke tests + description: Run Kibana test suite with FIPS agents links: - title: Pipeline link url: https://buildkite.com/elastic/kibana-fips @@ -16,10 +16,10 @@ spec: kind: Pipeline metadata: name: kibana / fips - description: Run Kibana FIPS smoke tests + description: Run Kibana test suite with FIPS agents spec: env: - SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-fips' ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' repository: elastic/kibana branch_configuration: main diff --git a/.buildkite/scripts/steps/checks/quick_checks.txt b/.buildkite/scripts/steps/checks/quick_checks.txt index 9bd9224673905..7aa0f68118466 100644 --- a/.buildkite/scripts/steps/checks/quick_checks.txt +++ b/.buildkite/scripts/steps/checks/quick_checks.txt @@ -17,3 +17,4 @@ .buildkite/scripts/steps/checks/prettier_topology.sh .buildkite/scripts/steps/checks/renovate.sh .buildkite/scripts/steps/checks/native_modules.sh +.buildkite/scripts/steps/checks/test_files_missing_owner.sh diff --git a/.buildkite/scripts/steps/checks/test_files_missing_owner.sh b/.buildkite/scripts/steps/checks/test_files_missing_owner.sh new file mode 100755 index 0000000000000..4dfec4e18ab61 --- /dev/null +++ b/.buildkite/scripts/steps/checks/test_files_missing_owner.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +echo --- Check for Test Files missing an owner +node scripts/check_ftr_code_owners diff --git a/.eslintrc.js b/.eslintrc.js index 7ff37b0c9fd98..226017e524d84 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2027,6 +2027,13 @@ module.exports = { '@kbn/imports/uniform_imports': 'off', }, }, + { + files: ['packages/kbn-dependency-ownership/**/*.{ts,tsx}'], + rules: { + // disabling it since package is a CLI tool + 'no-console': 'off', + }, + }, ], }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aef84a62485e3..6c70346b65ced 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -329,6 +329,7 @@ packages/kbn-data-service @elastic/kibana-visualizations @elastic/kibana-data-di packages/kbn-data-stream-adapter @elastic/security-threat-hunting packages/kbn-data-view-utils @elastic/kibana-data-discovery packages/kbn-datemath @elastic/kibana-data-discovery +packages/kbn-dependency-ownership @elastic/kibana-security packages/kbn-dependency-usage @elastic/kibana-security packages/kbn-dev-cli-errors @elastic/kibana-operations packages/kbn-dev-cli-runner @elastic/kibana-operations @@ -466,6 +467,7 @@ packages/kbn-rrule @elastic/response-ops packages/kbn-rule-data-utils @elastic/security-detections-response @elastic/response-ops @elastic/obs-ux-management-team packages/kbn-safer-lodash-set @elastic/kibana-security packages/kbn-saved-objects-settings @elastic/appex-sharedux +packages/kbn-saved-search-component @elastic/obs-ux-logs-team packages/kbn-scout @elastic/appex-qa packages/kbn-screenshotting-server @elastic/appex-sharedux packages/kbn-search-api-keys-components @elastic/search-kibana @@ -559,6 +561,7 @@ packages/react/kibana_context/styled @elastic/appex-sharedux packages/react/kibana_context/theme @elastic/appex-sharedux packages/react/kibana_mount @elastic/appex-sharedux packages/response-ops/feature_flag_service @elastic/response-ops +packages/response-ops/rule_form @elastic/response-ops packages/response-ops/rule_params @elastic/response-ops packages/serverless/project_switcher @elastic/appex-sharedux packages/serverless/settings/common @elastic/appex-sharedux @elastic/kibana-management @@ -620,7 +623,7 @@ packages/shared-ux/storybook/mock @elastic/appex-sharedux packages/shared-ux/table_persist @elastic/appex-sharedux src/core @elastic/kibana-core src/plugins/advanced_settings @elastic/appex-sharedux @elastic/kibana-management -src/plugins/ai_assistant_management/selection @elastic/obs-knowledge-team +src/plugins/ai_assistant_management/selection @elastic/obs-ai-assistant src/plugins/bfetch @elastic/appex-sharedux src/plugins/chart_expressions/common @elastic/kibana-visualizations src/plugins/chart_expressions/expression_gauge @elastic/kibana-visualizations @@ -865,6 +868,7 @@ x-pack/plugins/ai_infra/llm_tasks @elastic/appex-ai-infra x-pack/plugins/ai_infra/product_doc_base @elastic/appex-ai-infra x-pack/plugins/aiops @elastic/ml-ui x-pack/plugins/alerting @elastic/response-ops +x-pack/plugins/asset_inventory @elastic/kibana-cloud-security-posture x-pack/plugins/banners @elastic/appex-sharedux x-pack/plugins/canvas @elastic/kibana-presentation x-pack/plugins/cases @elastic/response-ops @@ -918,7 +922,7 @@ x-pack/plugins/monitoring @elastic/stack-monitoring x-pack/plugins/monitoring_collection @elastic/stack-monitoring x-pack/plugins/notifications @elastic/appex-sharedux x-pack/plugins/observability_solution/apm @elastic/obs-ux-infra_services-team -x-pack/plugins/observability_solution/apm_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team +x-pack/plugins/observability_solution/apm_data_access @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/apm/ftr_e2e @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/dataset_quality @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/entities_data_access @elastic/obs-entities @@ -929,10 +933,10 @@ x-pack/plugins/observability_solution/inventory @elastic/obs-ux-infra_services-t x-pack/plugins/observability_solution/inventory/e2e @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/investigate @elastic/obs-ux-management-team x-pack/plugins/observability_solution/investigate_app @elastic/obs-ux-management-team -x-pack/plugins/observability_solution/logs_data_access @elastic/obs-knowledge-team @elastic/obs-ux-logs-team +x-pack/plugins/observability_solution/logs_data_access @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/logs_explorer @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/logs_shared @elastic/obs-ux-logs-team -x-pack/plugins/observability_solution/metrics_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team +x-pack/plugins/observability_solution/metrics_data_access @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team x-pack/plugins/observability_solution/observability_ai_assistant @elastic/obs-ai-assistant x-pack/plugins/observability_solution/observability_ai_assistant_app @elastic/obs-ai-assistant @@ -978,8 +982,8 @@ x-pack/plugins/snapshot_restore @elastic/kibana-management x-pack/plugins/spaces @elastic/kibana-security x-pack/plugins/stack_alerts @elastic/response-ops x-pack/plugins/stack_connectors @elastic/response-ops -x-pack/plugins/streams @simianhacker @flash1293 @dgieselaar -x-pack/plugins/streams_app @simianhacker @flash1293 @dgieselaar +x-pack/plugins/streams @elastic/streams-program-team +x-pack/plugins/streams_app @elastic/streams-program-team x-pack/plugins/task_manager @elastic/response-ops x-pack/plugins/telemetry_collection_xpack @elastic/kibana-core x-pack/plugins/threat_intelligence @elastic/security-threat-hunting-investigations @@ -1134,6 +1138,7 @@ x-pack/test_serverless/api_integration/test_suites/common/platform_security @ela /x-pack/test_serverless/functional/test_suites/common/examples/unified_field_list_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/management/data_views @elastic/kibana-data-discovery src/plugins/discover/public/context_awareness/profile_providers/security @elastic/kibana-data-discovery @elastic/security-threat-hunting-investigations +src/plugins/discover/public/context_awareness/profile_providers/observability @elastic/kibana-data-discovery @elastic/obs-ux-logs-team # Platform Docs /x-pack/test_serverless/functional/test_suites/security/screenshot_creation/index.ts @elastic/platform-docs @@ -1234,6 +1239,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql # Observability UI +/x-pack/test/api_integration/apis/streams @elastic/observability-ui # Assigned per https://github.com/elastic/kibana/pull/201293 /x-pack/test_serverless/api_integration/test_suites/observability/config.ts @elastic/observability-ui @elastic/appex-qa /x-pack/test_serverless/api_integration/test_suites/observability/index.ts @elastic/observability-ui @@ -1285,6 +1291,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/plugins/observability_solution/infra/server/services @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/server/usage @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/server/utils @elastic/obs-ux-infra_services-team +/x-pack/test_serverless/functional/test_suites/observability/infra @elastic/obs-ux-infra_services-team /x-pack/test/api_integration/services/infraops_source_configuration.ts @elastic/obs-ux-infra_services-team @elastic/obs-ux-logs-team # Assigned per https://github.com/elastic/kibana/pull/34916 ## Logs UI code exceptions -> @elastic/obs-ux-logs-team @@ -2084,6 +2091,11 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints #CC# /x-pack/plugins/cross_cluster_replication/ @elastic/kibana-management # Security Solution +/x-pack/test/functional/fixtures/kbn_archiver/security_solution/timelines/7.15.0_space @elastic/security-solution # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_migrations.ts#L58 +/x-pack/test/functional/es_archives/packetbeat @elastic/security-solution +/x-pack/test/common/services/ingest_manager.ts @elastic/security-solution # Assigned per blame +/x-pack/test/security_solution_ftr @elastic/security-solution +/x-pack/test/functional/es_archives/security_solution @elastic/security-solution /x-pack/test/functional/es_archives/rule_exceptions @elastic/security-solution # Assigned per https://github.com/elastic/kibana/pull/199795/files/ae80bb252bc71f787c122849fcb9b01e386fc5e9#r1840233040 /x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts @elastic/security-solution /x-pack/test/common/utils/security_solution/index.ts @elastic/security-solution @@ -2092,7 +2104,9 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test/api_integration/services/security_solution_*.gen.ts @elastic/security-solution /x-pack/test/accessibility/apps/group3/security_solution.ts @elastic/security-solution /x-pack/test_serverless/functional/test_suites/security/config.ts @elastic/security-solution @elastic/appex-qa -/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts @elastic/security-solution +x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts @elastic/security-solution @elastic/appex-qa +x-pack/test_serverless/functional/test_suites/security/index.mki_only.ts @elastic/security-solution @elastic/appex-qa @elastic/kibana-cloud-security-posture +/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts @elastic/security-solution @elastic/kibana-cloud-security-posture /x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts @elastic/security-solution /x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts @elastic/security-solution /x-pack/test/functional/es_archives/endpoint/ @elastic/security-solution @@ -2123,11 +2137,15 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints # TODO: assign sub directories to sub teams /x-pack/plugins/security_solution_ess/ @elastic/security-solution /x-pack/plugins/security_solution_serverless/ @elastic/security-solution +/x-pack/plugins/security_solution/public/app/404.tsx @elastic/security-solution +/x-pack/plugins/security_solution/public/app/app.tsx @elastic/security-solution +/x-pack/plugins/security_solution/public/app/home @elastic/security-solution # GenAI in Security Solution /x-pack/plugins/security_solution/public/assistant @elastic/security-generative-ai /x-pack/plugins/security_solution/public/attack_discovery @elastic/security-generative-ai /x-pack/test/security_solution_cypress/cypress/e2e/ai_assistant @elastic/security-generative-ai +/x-pack/plugins/security_solution_ess/public/upselling/pages/attack_discovery @elastic/security-generative-ai # Security Solution cross teams ownership /x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting @@ -2143,6 +2161,8 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/plugins/security_solution/public/common/components/callouts @elastic/security-detections-response /x-pack/plugins/security_solution/public/common/components/hover_actions @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/formatted_date/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/formatted_number/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/server/routes @elastic/security-detections-response @elastic/security-threat-hunting /x-pack/plugins/security_solution/server/utils @elastic/security-detections-response @elastic/security-threat-hunting @@ -2173,6 +2193,7 @@ x-pack/test/security_solution_api_integration/test_suites/sources @elastic/secur /x-pack/plugins/security_solution/server/lib/siem_migrations @elastic/security-threat-hunting /x-pack/plugins/security_solution/common/siem_migrations @elastic/security-threat-hunting /x-pack/plugins/security_solution/public/siem_migrations @elastic/security-threat-hunting +/x-pack/plugins/security_solution/public/common/components/control_columns @elastic/security-threat-hunting ## Security Solution Threat Hunting areas - Threat Hunting Investigations @@ -2201,6 +2222,21 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/resolver @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/threat_intelligence @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/timelines @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/header_actions @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/common/types/header_actions @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/flyout/network_details @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/flyout/rule_details @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/investigations @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/drag_and_drop @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/draggables @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/events_tab @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution_serverless/public/upselling/pages/threat_intelligence_paywall.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/mock/mock_timeline_control_columns.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/exit_full_screen @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/app/home/template_wrapper/timeline @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/server/lib/timeline @elastic/security-threat-hunting-investigations @@ -2218,6 +2254,13 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/test/security_solution_cypress/cypress/tasks/network @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/app/actions @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/assets @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/app/solution_navigation/links @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/lib/clipboard @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/visualization_actions @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/accessibility @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/first_last_seen/first_last_seen.tsx @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/alert_count_by_status @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/charts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings @elastic/security-threat-hunting-explore @@ -2241,7 +2284,10 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/explore @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/overview @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/dashboards @elastic/security-threat-hunting-explore - +/x-pack/plugins/security_solution/public/onboarding @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/empty_page @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/empty_prompt @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network @elastic/security-threat-hunting-explore @@ -2313,6 +2359,7 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/detections/mitre @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/rules @elastic/security-detection-rule-management +/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions @elastic/security-detection-rule-management /x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations @elastic/security-detection-rule-management /x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules @elastic/security-detection-rule-management @@ -2335,6 +2382,8 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/test/functional/es_archives/entity/risks @elastic/security-detection-engine /x-pack/test/functional/es_archives/entity/host_risk @elastic/security-detection-engine /x-pack/test/api_integration/apis/lists @elastic/security-detection-engine +/x-pack/plugins/security_solution/public/value_list @elastic/security-detection-engine +/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout @elastic/security-detection-engine /x-pack/plugins/security_solution/public/sourcerer @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/detection_engine/rule_creation @elastic/security-detection-engine @@ -2390,6 +2439,8 @@ x-pack/packages/kbn-elastic-assistant-common/impl/schemas/defend_insights @elast x-pack/plugins/elastic_assistant/server/__mocks__/defend_insights_schema.mock.ts @elastic/security-defend-workflows x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/defend_insights @elastic/security-defend-workflows x-pack/plugins/elastic_assistant/server/routes/defend_insights @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/common/components/response_actions @elastic/security-defend-workflows +/x-pack/plugins/security_solution_serverless/public/upselling/pages/osquery_automated_response_actions.tsx @elastic/security-defend-workflows ## Security Solution sub teams - security-telemetry (Data Engineering) x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics @@ -2409,6 +2460,9 @@ x-pack/plugins/security_solution/common/api/entity_analytics @elastic/security-e ## Security Solution sub teams - GenAI x-pack/test/security_solution_api_integration/test_suites/genai @elastic/security-generative-ai +## Security Solution sub teams - Automatic Import +x-pack/test/automatic_import_api_integration @elastic/security-scalability + # Security Defend Workflows - OSQuery Ownership /x-pack/test/osquery_cypress @elastic/security-defend-workflows /x-pack/plugins/osquery @elastic/security-defend-workflows diff --git a/.i18nrc.json b/.i18nrc.json index 5c7642e6283eb..38629974722f3 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -117,7 +117,7 @@ "searchTypes": "packages/kbn-search-types", "securitySolutionPackages": "x-pack/packages/security-solution", "serverlessPackages": "packages/serverless", - "sse": [ "packages/kbn-sse-utils" ], + "sse": ["packages/kbn-sse-utils"], "coloring": "packages/kbn-coloring/src", "languageDocumentation": "packages/kbn-language-documentation/src", "esql": "src/plugins/esql", @@ -154,7 +154,8 @@ "unifiedDataTable": "packages/kbn-unified-data-table", "unsavedChangesBadge": "packages/kbn-unsaved-changes-badge", "unsavedChangesPrompt": "packages/kbn-unsaved-changes-prompt", - "managedContentBadge": "packages/kbn-managed-content-badge" + "managedContentBadge": "packages/kbn-managed-content-badge", + "responseOpsRuleForm": "packages/response-ops/rule_form" }, "translations": [] } diff --git a/api_docs/actions.devdocs.json b/api_docs/actions.devdocs.json index d93ecea54b849..551623f07d054 100644 --- a/api_docs/actions.devdocs.json +++ b/api_docs/actions.devdocs.json @@ -3270,20 +3270,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "actions", - "id": "def-server.ActionTypeExecutorOptions.isEphemeral", - "type": "CompoundType", - "tags": [], - "label": "isEphemeral", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/actions/server/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "actions", "id": "def-server.ActionTypeExecutorOptions.taskInfo", @@ -3838,16 +3824,6 @@ "ExecuteOptions", "[]) => Promise<", "ExecutionResponse", - ">; ephemeralEnqueuedExecution: (options: ", - "ExecuteOptions", - ") => Promise<", - { - "pluginId": "taskManager", - "scope": "server", - "docId": "kibTaskManagerPluginApi", - "section": "def-server.RunNowResult", - "text": "RunNowResult" - }, ">; listTypes: ({ featureId, includeSystemActionTypes, }?: ", "ListTypesParams", ") => Promise<", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 1af72b3008115..25325239da8cb 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 322 | 0 | 316 | 37 | +| 321 | 0 | 315 | 37 | ## Client diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index dff2ccf43c4a3..3ba1bc950dca4 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index 9f6ad0cf5fd3d..e6a25e9c32d37 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index f5cff24aa0f37..5a442711b0a1f 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-11-27 +date: 2024-12-03 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 0b009877a9f09..7e168f7bf1120 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -3701,6 +3701,17 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "alerting", + "id": "def-server.RuleExecutorOptions.isServerless", + "type": "boolean", + "tags": [], + "label": "isServerless", + "description": [], + "path": "x-pack/plugins/alerting/server/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4704,21 +4715,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-server.DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT", - "type": "number", - "tags": [], - "label": "DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT", - "description": [], - "signature": [ - "10" - ], - "path": "x-pack/plugins/alerting/server/config.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-server.ECS_COMPONENT_TEMPLATE_NAME", diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index ea2081402c007..3172ccf49b330 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 118ba322dff43..d9d9c62757559 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.devdocs.json b/api_docs/apm_data_access.devdocs.json index 6d0f3b4532dc4..be97ce96ca40e 100644 --- a/api_docs/apm_data_access.devdocs.json +++ b/api_docs/apm_data_access.devdocs.json @@ -441,6 +441,78 @@ ], "functions": [], "interfaces": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck", + "type": "Interface", + "tags": [], + "label": "ApmDataAccessPrivilegesCheck", + "description": [], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SecurityPluginStart", + "text": "SecurityPluginStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.getApmIndices", + "type": "Function", + "tags": [], + "label": "getApmIndices", + "description": [], + "signature": [ + "() => Promise>" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "apmDataAccess", "id": "def-server.ApmDataAccessServicesParams", @@ -2293,12 +2365,42 @@ "label": "getApmIndices", "description": [], "signature": [ - "() => Promise>" + "(soClient: ", + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsClientContract", + "text": "SavedObjectsClientContract" + }, + ") => Promise>" ], "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginSetup.getApmIndices.$1", + "type": "Object", + "tags": [], + "label": "soClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsClientContract", + "text": "SavedObjectsClientContract" + } + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], "returnComment": [] }, { @@ -2402,7 +2504,56 @@ "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginStart.hasPrivileges", + "type": "Function", + "tags": [], + "label": "hasPrivileges", + "description": [], + "signature": [ + "(params: Pick<", + { + "pluginId": "apmDataAccess", + "scope": "server", + "docId": "kibApmDataAccessPluginApi", + "section": "def-server.ApmDataAccessPrivilegesCheck", + "text": "ApmDataAccessPrivilegesCheck" + }, + ", \"request\">) => Promise" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginStart.hasPrivileges.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "apmDataAccess", + "scope": "server", + "docId": "kibApmDataAccessPluginApi", + "section": "def-server.ApmDataAccessPrivilegesCheck", + "text": "ApmDataAccessPrivilegesCheck" + }, + ", \"request\">" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], "lifecycle": "start", "initialIsOpen": true } diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index c0f09ed312e89..decef801d061d 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,20 +8,20 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) for questions regarding this plugin. **Code health stats** | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 86 | 0 | 86 | 3 | +| 93 | 0 | 93 | 3 | ## Server diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index f36af28bea528..37f6ffd3c560a 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-11-27 +date: 2024-12-03 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 0a2a25ea3e445..1574b0899679f 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-11-27 +date: 2024-12-03 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 f04ce5f1e088f..90d1aa548e6a8 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-11-27 +date: 2024-12-03 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 9880cdcacdce6..601841b63ddc3 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-11-27 +date: 2024-12-03 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 462e7c56bda55..5d341d4fb0450 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-11-27 +date: 2024-12-03 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 a709d1a7495a6..fae98a56939c8 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 21ddd0e8ab73e..eb5a95b7d2cc8 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index a6a3a9781ee0b..7646521c485d2 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 3c3f70caefbfe..dcf110b8af02c 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-11-27 +date: 2024-12-03 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 ac898d6ee80d2..ac3593719be3d 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 256dc282820a8..a6efce141f661 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 1bc423c63e004..3c954c4b17384 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 9bfe3a9e0565b..b25d90614eecb 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-11-27 +date: 2024-12-03 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 ce1fb30ca1562..01900e4b0d9c1 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-11-27 +date: 2024-12-03 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 6f639b739e299..c268fdfdf2193 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index aab2293d511c1..318ea50da0b48 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 706077120c014..f00b1f0ffbedd 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index cbd6a340d12b4..e6a4c20b9451d 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index e4477253a5fd0..ace239d289721 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_usage.mdx b/api_docs/data_usage.mdx index 97728ddd54b8f..ecf73aa12a4c4 100644 --- a/api_docs/data_usage.mdx +++ b/api_docs/data_usage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataUsage title: "dataUsage" image: https://source.unsplash.com/400x175/?github description: API docs for the dataUsage plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataUsage'] --- import dataUsageObj from './data_usage.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 032083eb9a848..d6af1159f4d8c 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-11-27 +date: 2024-12-03 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 3a4dbee621a68..d7f742560200e 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-11-27 +date: 2024-12-03 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 a2b7c6836d889..0a652e4195687 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 30a92a271fe9d..16737110a6685 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-11-27 +date: 2024-12-03 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 f35fc3a75bf27..e6599d0884ebf 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.devdocs.json b/api_docs/dataset_quality.devdocs.json index f6d641e428113..d160859f49a93 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -311,6 +311,24 @@ "DatasetQualityRouteHandlerResources", ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isIntegration: false; areAssetsAvailable: boolean; } | { isIntegration: true; areAssetsAvailable: true; integration: { name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; }; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -678,6 +696,24 @@ "DatasetQualityRouteHandlerResources", ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isIntegration: false; areAssetsAvailable: boolean; } | { isIntegration: true; areAssetsAvailable: true; integration: { name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; }; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { "pluginId": "@kbn/server-route-repository-utils", diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 1d5cb34fae0e8..c829741bc56c9 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index edb1f6ea44218..0d4d75b73171e 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -50,7 +50,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, @kbn/core, @kbn/alerting-types, alerting, actions, savedSearch, canvas, enterpriseSearch, securitySolution, taskManager, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, savedObjectsTagging, home, canvas, savedObjectsTaggingOss, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-ui-settings-server-internal | - | | | @kbn/core-saved-objects-migration-server-internal, dataViews, actions, data, alerting, dashboard, lens, cases, savedSearch, canvas, savedObjectsTagging, graph, lists, maps, visualizations, securitySolution, @kbn/core-test-helpers-so-type-serializer | - | -| | @kbn/esql-utils, @kbn/securitysolution-utils, securitySolution | - | | | security, securitySolution, cloudLinks, cases | - | | | security, cases, searchPlayground, securitySolution | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | @@ -167,18 +166,18 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-plugins-server-internal | - | | | encryptedSavedObjects | - | | | @kbn/esql-validation-autocomplete | - | +| | @kbn/esql-utils | - | | | @kbn/monaco | - | | | reporting | - | | | reporting | - | | | @kbn/reporting-export-types-pdf | - | -| | security, aiops, licenseManagement, ml, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher, profiling, apm, slo | 8.8.0 | +| | security, aiops, licenseManagement, ml, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher, slo | 8.8.0 | | | spaces, security, actions, alerting, aiops, remoteClusters, ml, graph, indexLifecycleManagement, osquery, securitySolution, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | spaces, @kbn/security-authorization-core, security, alerting, cases, @kbn/security-role-management-model | 8.8.0 | | | embeddable, presentationUtil, lens, dashboard, discover, graph, links | 8.8.0 | | | security, @kbn/security-role-management-model | 8.8.0 | -| | apm | 8.8.0 | | | security | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting @@ -223,6 +222,7 @@ Safe to remove. | | expressions | | | expressions | | | expressions | +| | home | | | home | | | kibanaReact | | | kibanaReact | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 22a2a3c343ef8..d38e73008c019 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -472,14 +472,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] -## @kbn/securitysolution-utils - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [compute_if_esql_query_aggregating.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts#:~:text=ast) | - | - - - ## @kbn/unified-field-list | Deprecated API | Reference location(s) | Remove By | @@ -538,9 +530,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/plugin.ts#:~:text=environment) | 8.8.0 | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | -| | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts#:~:text=authc), [get_agent_keys_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts#:~:text=authc), [is_superuser.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts#:~:text=authc), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts#:~:text=authc), [get_agent_keys_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts#:~:text=authc), [is_superuser.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts#:~:text=authc) | - | | | [apm_service_groups.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/saved_objects/apm_service_groups.ts#:~:text=migrations) | - | @@ -1173,7 +1163,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | | [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get) | - | @@ -1345,7 +1334,6 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject) | - | | | [timelines.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts#:~:text=migrations), [notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts#:~:text=migrations), [pinned_events.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts#:~:text=migrations), [legacy_saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts#:~:text=migrations), [saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/saved_object_mappings.ts#:~:text=migrations) | - | | | [timelines.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts#:~:text=convertToMultiNamespaceTypeVersion), [notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts#:~:text=convertToMultiNamespaceTypeVersion), [pinned_events.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts#:~:text=convertToMultiNamespaceTypeVersion), [legacy_saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | -| | [esql_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts#:~:text=ast), [esql_validator.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts#:~:text=ast) | - | | | [links.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/links.ts#:~:text=authc), [hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts#:~:text=authc) | - | | | [use_bulk_get_user_profiles.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.tsx#:~:text=userProfiles), [use_get_current_user_profile.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.tsx#:~:text=userProfiles) | - | | | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=audit), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin.ts#:~:text=audit), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin.ts#:~:text=audit) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index bae655128dd93..c42ccc11a88b8 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -97,9 +97,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| apm | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/plugin.ts#:~:text=environment) | 8.8.0 | | apm | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | -| apm | | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx#:~:text=license%24), [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | apm | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index f22ce6bf2ee7c..0b3e9a7f75b68 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 2eb8c1f28f089..51ca924813168 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -800,6 +800,1449 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices", + "type": "Interface", + "tags": [], + "label": "DiscoverServices", + "description": [], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.aiops", + "type": "Object", + "tags": [], + "label": "aiops", + "description": [], + "signature": [ + { + "pluginId": "aiops", + "scope": "public", + "docId": "kibAiopsPluginApi", + "section": "def-public.AiopsPluginStart", + "text": "AiopsPluginStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.application", + "type": "Object", + "tags": [], + "label": "application", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ApplicationStart", + "text": "ApplicationStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.addBasePath", + "type": "Function", + "tags": [], + "label": "addBasePath", + "description": [], + "signature": [ + "(path: string) => string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.addBasePath.$1", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.analytics", + "type": "Object", + "tags": [], + "label": "analytics", + "description": [], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: (eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.i18n", + "type": "Object", + "tags": [], + "label": "i18n", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-i18n-browser", + "scope": "public", + "docId": "kibKbnCoreI18nBrowserPluginApi", + "section": "def-public.I18nStart", + "text": "I18nStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.capabilities", + "type": "Object", + "tags": [], + "label": "capabilities", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.chrome", + "type": "Object", + "tags": [], + "label": "chrome", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.ChromeStart", + "text": "ChromeStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.core", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreStart", + "text": "CoreStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.data", + "type": "Object", + "tags": [], + "label": "data", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataPluginApi", + "section": "def-public.DataPublicPluginStart", + "text": "DataPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.discoverShared", + "type": "Object", + "tags": [], + "label": "discoverShared", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverSharedPublicStart", + "text": "DiscoverSharedPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.docLinks", + "type": "Object", + "tags": [], + "label": "docLinks", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-doc-links-browser", + "scope": "public", + "docId": "kibKbnCoreDocLinksBrowserPluginApi", + "section": "def-public.DocLinksStart", + "text": "DocLinksStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.history", + "type": "Object", + "tags": [], + "label": "history", + "description": [], + "signature": [ + "History", + "<", + "HistoryLocationState", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.getScopedHistory", + "type": "Function", + "tags": [], + "label": "getScopedHistory", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ScopedHistory", + "text": "ScopedHistory" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.setHeaderActionMenu", + "type": "Function", + "tags": [], + "label": "setHeaderActionMenu", + "description": [], + "signature": [ + "(menuMount: ", + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.MountPoint", + "text": "MountPoint" + }, + " | undefined) => void" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.setHeaderActionMenu.$1", + "type": "Function", + "tags": [], + "label": "menuMount", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.MountPoint", + "text": "MountPoint" + }, + " | undefined" + ], + "path": "packages/core/application/core-application-browser/src/app_mount.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.theme", + "type": "Object", + "tags": [], + "label": "theme", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-theme-browser", + "scope": "public", + "docId": "kibKbnCoreThemeBrowserPluginApi", + "section": "def-public.ThemeServiceSetup", + "text": "ThemeServiceSetup" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.filterManager", + "type": "Object", + "tags": [], + "label": "filterManager", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataQueryPluginApi", + "section": "def-public.FilterManager", + "text": "FilterManager" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.fieldFormats", + "type": "CompoundType", + "tags": [], + "label": "fieldFormats", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "fieldFormats", + "scope": "common", + "docId": "kibFieldFormatsPluginApi", + "section": "def-common.FieldFormatsRegistry", + "text": "FieldFormatsRegistry" + }, + ", \"init\" | \"register\"> & { deserialize: ", + { + "pluginId": "fieldFormats", + "scope": "common", + "docId": "kibFieldFormatsPluginApi", + "section": "def-common.FormatFactory", + "text": "FormatFactory" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViews", + "type": "Object", + "tags": [], + "label": "dataViews", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.inspector", + "type": "Object", + "tags": [], + "label": "inspector", + "description": [], + "signature": [ + { + "pluginId": "inspector", + "scope": "public", + "docId": "kibInspectorPluginApi", + "section": "def-public.Start", + "text": "Start" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [], + "signature": [ + "{ branch: string; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.navigation", + "type": "Object", + "tags": [], + "label": "navigation", + "description": [], + "signature": [ + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.NavigationPublicStart", + "text": "NavigationPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.share", + "type": "CompoundType", + "tags": [], + "label": "share", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "public", + "docId": "kibSharePluginApi", + "section": "def-public.SharePublicStart", + "text": "SharePublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.urlForwarding", + "type": "Object", + "tags": [], + "label": "urlForwarding", + "description": [], + "signature": [ + "{ navigateToLegacyKibanaUrl: (hash: string) => { navigated: boolean; }; getForwards: () => ", + { + "pluginId": "urlForwarding", + "scope": "public", + "docId": "kibUrlForwardingPluginApi", + "section": "def-public.ForwardDefinition", + "text": "ForwardDefinition" + }, + "[]; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.urlTracker", + "type": "Object", + "tags": [], + "label": "urlTracker", + "description": [], + "signature": [ + "UrlTracker" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.timefilter", + "type": "Object", + "tags": [], + "label": "timefilter", + "description": [], + "signature": [ + "{ isTimeRangeSelectorEnabled: () => boolean; isAutoRefreshSelectorEnabled: () => boolean; isTimeTouched: () => boolean; isRefreshIntervalTouched: () => boolean; getEnabledUpdated$: () => ", + "Observable", + "; getTimeUpdate$: () => ", + "Observable", + "; getRefreshIntervalUpdate$: () => ", + "Observable", + "; getAutoRefreshFetch$: () => ", + "Observable", + "<", + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataQueryPluginApi", + "section": "def-public.AutoRefreshDoneFn", + "text": "AutoRefreshDoneFn" + }, + ">; getFetch$: () => ", + "Observable", + "; getTime: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; getAbsoluteTime: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; setTime: (time: ", + "InputTimeRange", + ") => void; getRefreshInterval: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + ">) => void; createFilter: (indexPattern: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.RangeFilter", + "text": "RangeFilter" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.ScriptedRangeFilter", + "text": "ScriptedRangeFilter" + }, + " | ", + "MatchAllRangeFilter", + " | undefined; createRelativeFilter: (indexPattern: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.RangeFilter", + "text": "RangeFilter" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.ScriptedRangeFilter", + "text": "ScriptedRangeFilter" + }, + " | ", + "MatchAllRangeFilter", + " | undefined; getBounds: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + "; calculateBounds: (timeRange: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + ") => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + "; getActiveBounds: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + " | undefined; enableTimeRangeSelector: () => void; disableTimeRangeSelector: () => void; enableAutoRefreshSelector: () => void; disableAutoRefreshSelector: () => void; getTimeDefaults: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; getRefreshIntervalDefaults: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.toastNotifications", + "type": "Object", + "tags": [], + "label": "toastNotifications", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-notifications-browser", + "scope": "public", + "docId": "kibKbnCoreNotificationsBrowserPluginApi", + "section": "def-public.IToasts", + "text": "IToasts" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.notifications", + "type": "Object", + "tags": [], + "label": "notifications", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-notifications-browser", + "scope": "public", + "docId": "kibKbnCoreNotificationsBrowserPluginApi", + "section": "def-public.NotificationsStart", + "text": "NotificationsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "public", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-public.IUiSettingsClient", + "text": "IUiSettingsClient" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "public", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-public.SettingsStart", + "text": "SettingsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric", + "type": "Function", + "tags": [], + "label": "trackUiMetric", + "description": [], + "signature": [ + "((metricType: string, eventName: string | string[]) => void) | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric.$1", + "type": "string", + "tags": [], + "label": "metricType", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric.$2", + "type": "CompoundType", + "tags": [], + "label": "eventName", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViewFieldEditor", + "type": "Object", + "tags": [], + "label": "dataViewFieldEditor", + "description": [], + "signature": [ + { + "pluginId": "dataViewFieldEditor", + "scope": "public", + "docId": "kibDataViewFieldEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViewEditor", + "type": "Object", + "tags": [], + "label": "dataViewEditor", + "description": [], + "signature": [ + { + "pluginId": "dataViewEditor", + "scope": "public", + "docId": "kibDataViewEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataVisualizer", + "type": "Object", + "tags": [], + "label": "dataVisualizer", + "description": [], + "signature": [ + "{ getFileDataVisualizerComponent: () => Promise<() => ", + "SpecWithLinks", + ">>; getIndexDataVisualizerComponent: () => Promise<() => React.FC<", + "Props", + ">>; getDataDriftComponent: () => Promise<() => React.FC<", + "DataDriftDetectionAppStateProps", + ">>; getMaxBytesFormatted: () => string; FieldStatsUnavailableMessage: React.ForwardRefExoticComponent<{ id?: string | undefined; title?: string | undefined; } & React.RefAttributes<{}>>; FieldStatisticsTable: React.ForwardRefExoticComponent<", + "FieldStatisticTableEmbeddableProps", + " & React.RefAttributes<{}>>; } | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpSetup", + "text": "HttpSetup" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.storage", + "type": "Object", + "tags": [], + "label": "storage", + "description": [], + "signature": [ + { + "pluginId": "kibanaUtils", + "scope": "public", + "docId": "kibKibanaUtilsPluginApi", + "section": "def-public.Storage", + "text": "Storage" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.spaces", + "type": "Object", + "tags": [], + "label": "spaces", + "description": [], + "signature": [ + { + "pluginId": "spaces", + "scope": "public", + "docId": "kibSpacesPluginApi", + "section": "def-public.SpacesApi", + "text": "SpacesApi" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.triggersActionsUi", + "type": "Object", + "tags": [], + "label": "triggersActionsUi", + "description": [], + "signature": [ + { + "pluginId": "triggersActionsUi", + "scope": "public", + "docId": "kibTriggersActionsUiPluginApi", + "section": "def-public.TriggersAndActionsUIPublicPluginStart", + "text": "TriggersAndActionsUIPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.locator", + "type": "Object", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + }, + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.contextLocator", + "type": "Object", + "tags": [], + "label": "contextLocator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "DiscoverContextAppLocatorParams", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.singleDocLocator", + "type": "Object", + "tags": [], + "label": "singleDocLocator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "DiscoverSingleDocLocatorParams", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.expressions", + "type": "Object", + "tags": [], + "label": "expressions", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "public", + "docId": "kibExpressionsPluginApi", + "section": "def-public.ExpressionsStart", + "text": "ExpressionsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.charts", + "type": "CompoundType", + "tags": [], + "label": "charts", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "public", + "docId": "kibChartsPluginApi", + "section": "def-public.ChartsPluginSetup", + "text": "ChartsPluginSetup" + }, + " & { activeCursor: ", + "ActiveCursor", + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedObjectsManagement", + "type": "Object", + "tags": [], + "label": "savedObjectsManagement", + "description": [], + "signature": [ + { + "pluginId": "savedObjectsManagement", + "scope": "public", + "docId": "kibSavedObjectsManagementPluginApi", + "section": "def-public.SavedObjectsManagementPluginStart", + "text": "SavedObjectsManagementPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedObjectsTagging", + "type": "Object", + "tags": [], + "label": "savedObjectsTagging", + "description": [], + "signature": [ + { + "pluginId": "savedObjectsTaggingOss", + "scope": "public", + "docId": "kibSavedObjectsTaggingOssPluginApi", + "section": "def-public.SavedObjectsTaggingApi", + "text": "SavedObjectsTaggingApi" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedSearch", + "type": "Object", + "tags": [], + "label": "savedSearch", + "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearchPublicPluginStart", + "text": "SavedSearchPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.unifiedSearch", + "type": "Object", + "tags": [], + "label": "unifiedSearch", + "description": [], + "signature": [ + { + "pluginId": "unifiedSearch", + "scope": "public", + "docId": "kibUnifiedSearchPluginApi", + "section": "def-public.UnifiedSearchPublicPluginStart", + "text": "UnifiedSearchPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.lens", + "type": "Object", + "tags": [], + "label": "lens", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensPublicStart", + "text": "LensPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.uiActions", + "type": "Object", + "tags": [], + "label": "uiActions", + "description": [], + "signature": [ + "{ readonly registerTrigger: (trigger: ", + { + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" + }, + ") => void; readonly hasTrigger: (triggerId: string) => boolean; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" + }, + ") => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" + }, + ") => void; readonly getAction: (id: string) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "; readonly getTriggerActions: (triggerId: string) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]; readonly getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]>; readonly getFrequentlyChangingActionsForTrigger: (triggerId: string, context: object) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.FrequentCompatibilityChangeAction", + "text": "FrequentCompatibilityChangeAction" + }, + "[]; readonly executeTriggerActions: (triggerId: string, context: object) => Promise; readonly clear: () => void; readonly fork: () => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.UiActionsService", + "text": "UiActionsService" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.contentClient", + "type": "Object", + "tags": [], + "label": "contentClient", + "description": [], + "signature": [ + { + "pluginId": "contentManagement", + "scope": "public", + "docId": "kibContentManagementPluginApi", + "section": "def-public.ContentClient", + "text": "ContentClient" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.noDataPage", + "type": "Object", + "tags": [], + "label": "noDataPage", + "description": [], + "signature": [ + { + "pluginId": "noDataPage", + "scope": "public", + "docId": "kibNoDataPagePluginApi", + "section": "def-public.NoDataPagePublicSetup", + "text": "NoDataPagePublicSetup" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.observabilityAIAssistant", + "type": "Object", + "tags": [], + "label": "observabilityAIAssistant", + "description": [], + "signature": [ + { + "pluginId": "observabilityAIAssistant", + "scope": "public", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-public.ObservabilityAIAssistantPublicStart", + "text": "ObservabilityAIAssistantPublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.profilesManager", + "type": "Object", + "tags": [], + "label": "profilesManager", + "description": [], + "signature": [ + "ProfilesManager" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.ebtManager", + "type": "Object", + "tags": [], + "label": "ebtManager", + "description": [], + "signature": [ + "DiscoverEBTManager" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.fieldsMetadata", + "type": "Object", + "tags": [], + "label": "fieldsMetadata", + "description": [], + "signature": [ + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.logsDataAccess", + "type": "Object", + "tags": [], + "label": "logsDataAccess", + "description": [], + "signature": [ + "{ services: { logSourcesService: ", + "LogSourcesService", + "; }; } | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.DiscoverStateContainer", @@ -1289,6 +2732,48 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions", + "type": "Interface", + "tags": [], + "label": "NonPersistedDisplayOptions", + "description": [], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions.enableDocumentViewer", + "type": "CompoundType", + "tags": [], + "label": "enableDocumentViewer", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions.enableFilters", + "type": "CompoundType", + "tags": [], + "label": "enableFilters", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.PublishesSavedSearch", @@ -1871,7 +3356,13 @@ "description": [], "signature": [ "{ isLoading?: boolean | undefined; overrideServices: Partial<", - "DiscoverServices", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.DiscoverServices", + "text": "DiscoverServices" + }, ">; scopedHistory: ", { "pluginId": "@kbn/core-application-browser", @@ -1982,6 +3473,239 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.SearchEmbeddableApi", + "type": "Type", + "tags": [], + "label": "SearchEmbeddableApi", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.DefaultEmbeddableApi", + "text": "DefaultEmbeddableApi" + }, + "<", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.SearchEmbeddableSerializedState", + "text": "SearchEmbeddableSerializedState" + }, + ", ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.SearchEmbeddableRuntimeState", + "text": "SearchEmbeddableRuntimeState" + }, + "> & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesSavedObjectId", + "text": "PublishesSavedObjectId" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataLoading", + "text": "PublishesDataLoading" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesBlockingError", + "text": "PublishesBlockingError" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesPanelTitle", + "text": "PublishesPanelTitle" + }, + " & { setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; } & ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.PublishesSavedSearch", + "text": "PublishesSavedSearch" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataViews", + "text": "PublishesDataViews" + }, + " & { setDataViews: (dataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]) => void; } & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesTimeRange", + "text": "PublishesTimeRange" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesFilters", + "text": "PublishesFilters" + }, + " & { isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined>; } & { setTimeRange: (timeRange: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => void; } & { setFilters: (filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined) => void; setQuery: (query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined) => void; } & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.HasInPlaceLibraryTransforms", + "text": "HasInPlaceLibraryTransforms" + }, + " & ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.HasTimeRange", + "text": "HasTimeRange" + }, + " & Partial<", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.HasEditCapabilities", + "text": "HasEditCapabilities" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesSavedObjectId", + "text": "PublishesSavedObjectId" + }, + ">" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "discover", + "id": "def-public.SearchEmbeddableRuntimeState", + "type": "Type", + "tags": [], + "label": "SearchEmbeddableRuntimeState", + "description": [], + "signature": [ + "Omit<", + "SearchEmbeddableState", + ", \"rows\" | \"searchSource\" | \"columnsMeta\" | \"totalHitCount\"> & Pick<", + "SerializableSavedSearch", + ", \"serializedSearchSource\"> & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.SerializedTitles", + "text": "SerializedTitles" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.SerializedTimeRange", + "text": "SerializedTimeRange" + }, + " & { savedObjectTitle?: string | undefined; savedObjectId?: string | undefined; savedObjectDescription?: string | undefined; nonPersistedDisplayOptions?: ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined; }" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.SearchEmbeddableSerializedState", @@ -2019,7 +3743,15 @@ "section": "def-common.SavedObjectReference", "text": "SavedObjectReference" }, - "[] | undefined; }) | undefined; savedObjectId?: string | undefined; }" + "[] | undefined; }) | undefined; savedObjectId?: string | undefined; nonPersistedDisplayOptions?: ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined; }" ], "path": "src/plugins/discover/public/embeddable/types.ts", "deprecated": false, diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 6e2b0ef563877..dc4c2a117f6c2 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 148 | 0 | 100 | 24 | +| 214 | 0 | 166 | 30 | ## Client diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 3891c505a5354..dd1634e549f7b 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.devdocs.json b/api_docs/discover_shared.devdocs.json index bc05a07a26fee..39dc71aa37b16 100644 --- a/api_docs/discover_shared.devdocs.json +++ b/api_docs/discover_shared.devdocs.json @@ -4,6 +4,94 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceSetup", + "type": "Interface", + "tags": [], + "label": "DiscoverFeaturesServiceSetup", + "description": [ + "\nService types" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceSetup.registry", + "type": "Object", + "tags": [], + "label": "registry", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "common", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-common.FeaturesRegistry", + "text": "FeaturesRegistry" + }, + "<", + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeature", + "text": "DiscoverFeature" + }, + ">" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceStart", + "type": "Interface", + "tags": [], + "label": "DiscoverFeaturesServiceStart", + "description": [], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceStart.registry", + "type": "Object", + "tags": [], + "label": "registry", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "common", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-common.FeaturesRegistry", + "text": "FeaturesRegistry" + }, + "<", + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeature", + "text": "DiscoverFeature" + }, + ">" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discoverShared", "id": "def-public.ObservabilityLogsAIAssistantFeature", @@ -113,6 +201,104 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature", + "type": "Interface", + "tags": [], + "label": "SecuritySolutionAppWrapperFeature", + "description": [], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"security-solution-app-wrapper\"" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature.getWrapper", + "type": "Function", + "tags": [], + "label": "getWrapper", + "description": [], + "signature": [ + "() => Promise<() => React.FunctionComponent<{ children?: React.ReactNode; }>>" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature", + "type": "Interface", + "tags": [], + "label": "SecuritySolutionCellRendererFeature", + "description": [ + "*************** Security Solution" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"security-solution-cell-renderer\"" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature.getRenderer", + "type": "Function", + "tags": [], + "label": "getRenderer", + "description": [], + "signature": [ + "() => Promise<(fieldName: string) => React.FunctionComponent<", + { + "pluginId": "@kbn/unified-data-table", + "scope": "public", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-public.DataGridCellValueElementProps", + "text": "DataGridCellValueElementProps" + }, + "> | undefined>" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false } ], "enums": [], @@ -133,7 +319,9 @@ "text": "ObservabilityLogsAIAssistantFeature" }, " | ", - "ObservabilityCreateSLOFeature" + "ObservabilityCreateSLOFeature", + " | ", + "SecuritySolutionFeature" ], "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", "deprecated": false, @@ -161,7 +349,13 @@ "label": "features", "description": [], "signature": [ - "DiscoverFeaturesServiceSetup" + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeaturesServiceSetup", + "text": "DiscoverFeaturesServiceSetup" + } ], "path": "src/plugins/discover_shared/public/types.ts", "deprecated": false, @@ -190,7 +384,13 @@ "label": "features", "description": [], "signature": [ - "DiscoverFeaturesServiceStart" + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeaturesServiceStart", + "text": "DiscoverFeaturesServiceStart" + } ], "path": "src/plugins/discover_shared/public/types.ts", "deprecated": false, diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index e37ba8b72d2c8..0f6288b8ea946 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 15 | 3 | +| 26 | 0 | 23 | 2 | ## Client diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 7546e62ff5805..98377a0807c98 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index f873e33685b8a..7a0831a5debfe 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 2cb11c0116c0f..7774b8b0a3c5d 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-11-27 +date: 2024-12-03 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 65d1808e2079b..2439bde8e99de 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-11-27 +date: 2024-12-03 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 0d2906a9006ef..32a3d89f65a24 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-11-27 +date: 2024-12-03 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 c658209a8e920..230c232342c75 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index 7b8b5a3bcb709..fb7b4c912b45e 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.devdocs.json b/api_docs/entity_manager.devdocs.json index 7895ae318fb61..fb4d3e8050c6f 100644 --- a/api_docs/entity_manager.devdocs.json +++ b/api_docs/entity_manager.devdocs.json @@ -37,7 +37,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray>; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { @@ -63,7 +63,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }, { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { @@ -385,7 +385,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray>; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { @@ -411,7 +411,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }, { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { @@ -922,6 +922,48 @@ ], "returnComment": [] }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getEntityDefinition", + "type": "Function", + "tags": [], + "label": "getEntityDefinition", + "description": [], + "signature": [ + "(id: string) => Promise<{ definitions: { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }[] | ", + "EntityDefinitionWithState", + "[]; }>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getEntityDefinition.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "entityManager", "id": "def-public.EntityClient.asKqlFilter", @@ -1250,7 +1292,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray>; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; timestamp_field: string; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; }[]; limit: number; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; limit?: number | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { @@ -1276,7 +1318,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }, { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index 37d1a95b38ca5..3711c94ed9ba3 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entiti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 35 | 0 | 35 | 2 | +| 37 | 0 | 37 | 3 | ## Client diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index b4f6310795e82..1d5cd9990b9db 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index 1ff01377ceecd..d026d789d73ae 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index ee17fed28aa2c..4cd5976f886ca 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 512c48d16d574..60c63d315f8f7 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 3597c9456c45c..006a0ad52e329 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 6922f107521ff..90bed851be237 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 4ab3268b69fb0..d226a1207d3fc 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 2b92ecc7c116c..5412c012dccf0 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-11-27 +date: 2024-12-03 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 07e46314f6dc8..0be715deea203 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-11-27 +date: 2024-12-03 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 642f11b48b11f..c7882909785de 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-11-27 +date: 2024-12-03 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 0b82a721235bf..c9332d0b0ff68 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-11-27 +date: 2024-12-03 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 04a228b8bf64b..e83cea3de90cb 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-11-27 +date: 2024-12-03 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 6426bbde44e52..872ef40b76e34 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-11-27 +date: 2024-12-03 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 047898c9af166..b3c82de9aaed6 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-11-27 +date: 2024-12-03 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 47846e49f0294..8c1e1462e9ee5 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-11-27 +date: 2024-12-03 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 04a5b613dfef9..fe3383781dd3c 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-11-27 +date: 2024-12-03 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 a56473b55277e..585fdceb1ae5a 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-11-27 +date: 2024-12-03 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 4d846ea86ef13..3c46e5108b05f 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-11-27 +date: 2024-12-03 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 870e6f696600b..1ab84e554d867 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-11-27 +date: 2024-12-03 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 f0fa1a9ee98ad..c63d33f62a1cb 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index ad39d061cd0b8..f7433b89be8a4 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index b215ab126a723..b4cab32461bd3 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 074a62ae66498..d3a77744d9383 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index 9cb724cf855e8..7700b42a9da68 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index b07fceaa4a177..2169567dd27db 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 98bce55a733be..c7568eef46d7f 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index a84ed93c2cf36..ebcc2d578f6ca 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 670bd13f2f0c9..9abcedefd3043 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -9243,6 +9243,61 @@ ], "returnComment": [] }, + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo", + "type": "Function", + "tags": [], + "label": "getLatestPackageInfo", + "description": [], + "signature": [ + "(packageName: string, prerelease?: boolean | undefined) => Promise<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.PackageInfo", + "text": "PackageInfo" + }, + ">" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo.$1", + "type": "string", + "tags": [], + "label": "packageName", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo.$2", + "type": "CompoundType", + "tags": [], + "label": "prerelease", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, { "parentPluginId": "fleet", "id": "def-server.PackageClient.getPackages", diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 3fd29588aaf81..1c4db3adeae7d 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1432 | 5 | 1306 | 82 | +| 1435 | 5 | 1309 | 82 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 17c24ae64081a..229d3a9e4bbb7 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-11-27 +date: 2024-12-03 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 d6934ecb7ec2d..7824e377774e3 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.devdocs.json b/api_docs/home.devdocs.json index 1b22af8001d6b..797a06a30715b 100644 --- a/api_docs/home.devdocs.json +++ b/api_docs/home.devdocs.json @@ -1415,12 +1415,7 @@ "deprecated": true, "removeBy": "8.8.0", "trackAdoption": false, - "references": [ - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/public/plugin.ts" - } - ] + "references": [] } ], "lifecycle": "setup", diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 040a44a679925..7dc920164d8d1 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 527af733a2c34..67b9a220830bd 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index e37f8a9d3acfd..56da4fb40641c 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-11-27 +date: 2024-12-03 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 522ab22701225..2e82880526e59 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/inference.devdocs.json b/api_docs/inference.devdocs.json index 340b5e87d7f0d..4cf16dcfec9bf 100644 --- a/api_docs/inference.devdocs.json +++ b/api_docs/inference.devdocs.json @@ -738,11 +738,13 @@ "type": "Function", "tags": [], "label": "correctCommonEsqlMistakes", - "description": [], + "description": [ + "\nCorrect some common ES|QL syntax and grammar mistakes that LLM can potentially do.\n\nCorrecting the query is done in two steps:\n1. we try to correct the *syntax*, without AST (given it requires a valid syntax)\n2. we try to correct the *grammar*, using AST this time." + ], "signature": [ - "(query: string) => { isCorrection: boolean; input: string; output: string; }" + "(query: string) => { input: string; output: string; isCorrection: boolean; }" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -756,7 +758,7 @@ "signature": [ "string" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -929,7 +931,7 @@ "signature": [ "(query: string) => { name: string | undefined; command: string; }[]" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -943,7 +945,7 @@ "signature": [ "string" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts", "deprecated": false, "trackAdoption": false, "isRequired": true diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index ffde710c0a2d3..ec0fa9af52514 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 40 | 0 | 29 | 6 | +| 40 | 0 | 28 | 6 | ## Client diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 85cd3c13d2fe6..76d0e667edacf 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index 94bac60dd1a98..7c385f03d849f 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index a2c84995a7041..453e6fba686db 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.devdocs.json b/api_docs/integration_assistant.devdocs.json index 37870e95e8e94..3c6f41d4c4c03 100644 --- a/api_docs/integration_assistant.devdocs.json +++ b/api_docs/integration_assistant.devdocs.json @@ -318,7 +318,7 @@ "label": "AnalyzeLogsResponse", "description": [], "signature": [ - "{ results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + "{ results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -357,7 +357,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }" ], "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.gen.ts", "deprecated": false, @@ -384,7 +384,7 @@ "label": "CategorizationRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -581,7 +581,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -625,7 +625,7 @@ "label": "EcsMappingRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -714,7 +714,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -848,7 +848,7 @@ "label": "RelatedRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -912,7 +912,7 @@ "\nFormat of the provided log samples." ], "signature": [ - "{ name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }" + "{ name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -929,7 +929,7 @@ "\nThe name of the log samples format." ], "signature": [ - "\"ndjson\" | \"json\" | \"csv\" | \"structured\" | \"unstructured\" | \"unsupported\"" + "\"ndjson\" | \"json\" | \"csv\" | \"structured\" | \"unstructured\" | \"unsupported\" | \"cef\"" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -971,7 +971,7 @@ }, ", Zod.ZodTypeDef, ", "ESProcessorItemInput", - ">, \"many\">>; results: Zod.ZodObject<{ samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; parsedSamples: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + ">, \"many\">>; results: Zod.ZodObject<{ samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; parsedSamples: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -979,7 +979,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + "[] | undefined; }, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", "ESProcessorItemInput", "[] | undefined; }>" ], @@ -1036,7 +1036,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1052,11 +1052,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1072,11 +1072,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1092,11 +1092,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.gen.ts", "deprecated": false, @@ -1151,7 +1151,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1167,7 +1167,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", @@ -1456,7 +1456,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1472,11 +1472,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -1506,7 +1506,7 @@ "label": "EcsMappingRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ packageName: Zod.ZodString; dataStreamName: Zod.ZodString; rawSamples: Zod.ZodArray; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; mapping: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; additionalProcessors: Zod.ZodOptional; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; mapping: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; additionalProcessors: Zod.ZodOptional, \"many\">>; connectorId: Zod.ZodString; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + ">, \"many\">>; connectorId: Zod.ZodString; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1524,7 +1524,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + "[] | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", "ESProcessorItemInput", "[] | undefined; }>" ], @@ -1716,7 +1716,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1732,11 +1732,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1752,11 +1752,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -1881,7 +1881,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1897,7 +1897,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", @@ -2011,7 +2011,7 @@ "label": "SamplesFormat", "description": [], "signature": [ - "Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>" + "Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -2026,7 +2026,7 @@ "label": "SamplesFormatName", "description": [], "signature": [ - "Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>" + "Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 0a5651ecd100d..8d8a9090a8272 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 4d7491ee0baa1..8a5c806b2c6a6 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/inventory.devdocs.json b/api_docs/inventory.devdocs.json index 00f3e7b5b9b81..39c0d7b7c7b69 100644 --- a/api_docs/inventory.devdocs.json +++ b/api_docs/inventory.devdocs.json @@ -82,9 +82,13 @@ "PartialC", "<{ query: ", "PartialC", - "<{ esQuery: ", + "<{ includeEntityTypes: ", "Type", - "<{ [key: string]: unknown; }, string, unknown>; }>; }>]>, ", + "; excludeEntityTypes: ", + "Type", + "; kuery: ", + "StringC", + "; }>; }>]>, ", "InventoryRouteHandlerResources", ", { groupBy: \"entity.type\"; groups: ", "EntityGroup", @@ -136,9 +140,9 @@ "LiteralC", "<\"desc\">]>; }>, ", "PartialC", - "<{ esQuery: ", - "Type", - "<{ [key: string]: unknown; }, string, unknown>; entityTypes: ", + "<{ kuery: ", + "StringC", + "; entityTypes: ", "Type", "; }>]>; }>, ", "InventoryRouteHandlerResources", diff --git a/api_docs/inventory.mdx b/api_docs/inventory.mdx index 273f67f8ea2b4..aadd2ea61f55f 100644 --- a/api_docs/inventory.mdx +++ b/api_docs/inventory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inventory title: "inventory" image: https://source.unsplash.com/400x175/?github description: API docs for the inventory plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inventory'] --- import inventoryObj from './inventory.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index fca5864701e25..655656d8e900c 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index 1848c3f701814..8d11653091be4 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index 9b3f8a9d646ea..bc6e94cfac6eb 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_ai_assistant.mdx b/api_docs/kbn_ai_assistant.mdx index 0cab1026c7f3c..c683aeba68730 100644 --- a/api_docs/kbn_ai_assistant.mdx +++ b/api_docs/kbn_ai_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant title: "@kbn/ai-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant'] --- import kbnAiAssistantObj from './kbn_ai_assistant.devdocs.json'; diff --git a/api_docs/kbn_ai_assistant_common.mdx b/api_docs/kbn_ai_assistant_common.mdx index 57f7a87d68552..f19f97a4449f4 100644 --- a/api_docs/kbn_ai_assistant_common.mdx +++ b/api_docs/kbn_ai_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant-common title: "@kbn/ai-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant-common'] --- import kbnAiAssistantCommonObj from './kbn_ai_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.devdocs.json b/api_docs/kbn_aiops_components.devdocs.json index 90b929e81e677..fc526124b270a 100644 --- a/api_docs/kbn_aiops_components.devdocs.json +++ b/api_docs/kbn_aiops_components.devdocs.json @@ -703,6 +703,22 @@ "path": "x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/aiops-components", + "id": "def-common.DocumentCountChartProps.nonInteractive", + "type": "CompoundType", + "tags": [], + "label": "nonInteractive", + "description": [ + "Whether the brush should be non-interactive" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 767e0b9ee8050..f97b1a673f4e3 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 0 | 0 | 0 | +| 37 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index 1191a5a8568ed..fbac611741b86 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index 5227a07210eb9..3dd810cf505b6 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 9558893fcb150..55bf830ff7842 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index 893104c554789..4accc32a4deb3 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 7093f00983bfb..44f688a7bb5da 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 2938be91e1f4d..e086a27730597 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 5b1a87f57997f..5e51f13103f95 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index 15eeb742f7e8c..2e75a8a1181f0 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.devdocs.json b/api_docs/kbn_alerts_ui_shared.devdocs.json index 402f4ad328ac8..b186a273e1dd4 100644 --- a/api_docs/kbn_alerts_ui_shared.devdocs.json +++ b/api_docs/kbn_alerts_ui_shared.devdocs.json @@ -5203,6 +5203,20 @@ "path": "packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-public.UseLoadConnectorTypesProps.featureId", + "type": "string", + "tags": [], + "label": "featureId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 0342e40d38248..9e573d9868d5b 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 320 | 0 | 304 | 8 | +| 321 | 0 | 305 | 8 | ## Client diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index d8e0e6880b553..4920c2b74d82b 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index 656c6b899aed1..e31437c87d60f 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index eafced76fa563..6f3489930119d 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-11-27 +date: 2024-12-03 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_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 83169deb8a9f3..11f911917bf01 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 0d080c897d9fd..77ca49ee9a36a 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 00a9056b8eff1..41bd4c9ae2481 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index f836b23122901..55b6b16418ba0 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 37f8d0f9b47b1..4075db91aeeb5 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index 4e772e92474fb..b601c38a6b6f2 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index e710b9fa41b63..015b7e6fc4655 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 7cd9343a61272..b1f7af0142da9 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index aeea69a32b418..9aee2ea98ae3c 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 8494d0e0d4032..773c0ec8ab72b 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 50e85f2ea5197..8b250e1427d25 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx index edcd2a3f7fff4..f4d4502cdc37b 100644 --- a/api_docs/kbn_cbor.mdx +++ b/api_docs/kbn_cbor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cbor title: "@kbn/cbor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cbor plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] --- import kbnCborObj from './kbn_cbor.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index db018a5e4a3d7..0e297dede197c 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index fc2ec2c32a3b9..a5e272dd9b74d 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 2f5ba230bc9cd..8d943b0d72a6a 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-11-27 +date: 2024-12-03 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 6de2b39b815aa..41b41e8befbf2 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-11-27 +date: 2024-12-03 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 dc83a1c1fb9ac..31077f7f51401 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-11-27 +date: 2024-12-03 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 82914e9a4c3d6..043bf8e005c29 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-11-27 +date: 2024-12-03 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 010251355c4b0..aa15347482fc0 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture.devdocs.json b/api_docs/kbn_cloud_security_posture.devdocs.json index 37cc79e0d28b8..62f5fce1db937 100644 --- a/api_docs/kbn_cloud_security_posture.devdocs.json +++ b/api_docs/kbn_cloud_security_posture.devdocs.json @@ -270,7 +270,7 @@ "label": "getVulnerabilityStats", "description": [], "signature": [ - "(counts: VulnerabilityCounts) => VulnerabilitiesDistributionBarProps[]" + "(counts: VulnerabilityCounts, filterFunction?: ((filter: string) => void) | undefined, currentFilter?: string | undefined) => VulnerabilitiesDistributionBarProps[]" ], "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", "deprecated": false, @@ -290,6 +290,36 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.getVulnerabilityStats.$2", + "type": "Function", + "tags": [], + "label": "filterFunction", + "description": [], + "signature": [ + "((filter: string) => void) | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.getVulnerabilityStats.$3", + "type": "string", + "tags": [], + "label": "currentFilter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -444,9 +474,9 @@ "label": "query", "description": [], "signature": [ - "{ bool: { filter: ", + "{ bool: { filter: (", "QueryDslQueryContainer", - "[]; }; } | undefined" + " | undefined)[] | undefined; }; } | undefined" ], "path": "x-pack/packages/kbn-cloud-security-posture/public/src/types.ts", "deprecated": false, @@ -1042,6 +1072,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.HOST_NAME", + "type": "string", + "tags": [], + "label": "HOST_NAME", + "description": [], + "signature": [ + "\"host.name\"" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture", "id": "def-public.LatestFindingsRequest", @@ -1120,6 +1165,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.USER_NAME", + "type": "string", + "tags": [], + "label": "USER_NAME", + "description": [], + "signature": [ + "\"user.name\"" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [ diff --git a/api_docs/kbn_cloud_security_posture.mdx b/api_docs/kbn_cloud_security_posture.mdx index 6ae3155af9761..9a9ebb3ed96a5 100644 --- a/api_docs/kbn_cloud_security_posture.mdx +++ b/api_docs/kbn_cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture title: "@kbn/cloud-security-posture" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 89 | 1 | 89 | 0 | +| 93 | 1 | 93 | 0 | ## Client diff --git a/api_docs/kbn_cloud_security_posture_common.devdocs.json b/api_docs/kbn_cloud_security_posture_common.devdocs.json index 6c0ae2a2db8aa..5e993b4e3c1f3 100644 --- a/api_docs/kbn_cloud_security_posture_common.devdocs.json +++ b/api_docs/kbn_cloud_security_posture_common.devdocs.json @@ -129,13 +129,13 @@ "functions": [ { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery", "type": "Function", "tags": [], - "label": "buildEntityFlyoutPreviewQuery", + "label": "buildGenericEntityFlyoutPreviewQuery", "description": [], "signature": [ - "(field: string, queryValue?: string | undefined) => { bool: { filter: { bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; }[]; }; }" + "(field: string, queryValue?: string | undefined, status?: string | undefined, queryField?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" ], "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", "deprecated": false, @@ -143,7 +143,7 @@ "children": [ { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery.$1", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$1", "type": "string", "tags": [], "label": "field", @@ -158,7 +158,7 @@ }, { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery.$2", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$2", "type": "string", "tags": [], "label": "queryValue", @@ -170,6 +170,99 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$4", + "type": "string", + "tags": [], + "label": "queryField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery", + "type": "Function", + "tags": [], + "label": "buildMisconfigurationEntityFlyoutPreviewQuery", + "description": [], + "signature": [ + "(field: string, queryValue?: string | undefined, status?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$2", + "type": "string", + "tags": [], + "label": "queryValue", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -210,6 +303,69 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery", + "type": "Function", + "tags": [], + "label": "buildVulnerabilityEntityFlyoutPreviewQuery", + "description": [], + "signature": [ + "(field: string, queryValue?: string | undefined, status?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$2", + "type": "string", + "tags": [], + "label": "queryValue", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.extractErrorMessage", @@ -1556,6 +1712,42 @@ } ], "objects": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS", + "type": "Object", + "tags": [], + "label": "MISCONFIGURATION_STATUS", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS.PASSED", + "type": "string", + "tags": [], + "label": "PASSED", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS.FAILED", + "type": "string", + "tags": [], + "label": "FAILED", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.VULNERABILITIES_SEVERITY", diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index 5a46e89634035..0c9d0ce05e98f 100644 --- a/api_docs/kbn_cloud_security_posture_common.mdx +++ b/api_docs/kbn_cloud_security_posture_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-common title: "@kbn/cloud-security-posture-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 109 | 0 | 107 | 1 | +| 122 | 0 | 120 | 1 | ## Common diff --git a/api_docs/kbn_cloud_security_posture_graph.mdx b/api_docs/kbn_cloud_security_posture_graph.mdx index 927e3e25db4a5..5bdb2f2922367 100644 --- a/api_docs/kbn_cloud_security_posture_graph.mdx +++ b/api_docs/kbn_cloud_security_posture_graph.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-graph title: "@kbn/cloud-security-posture-graph" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-graph plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-graph'] --- import kbnCloudSecurityPostureGraphObj from './kbn_cloud_security_posture_graph.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 08dc56065ab88..5f2d76f06ed33 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 606e20a95a25b..4dfe3de38b27e 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index a23494a4a8cb0..77f579431d482 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index de1f4714d7529..040e0b7ca3ef8 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-11-27 +date: 2024-12-03 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 dd0c09d765a09..34eb1c16afdf9 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-11-27 +date: 2024-12-03 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 36df24c2e2f44..afdf13e4fd5b1 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 b26095053d9f0..b7f38ac879ff8 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 604ac3659af34..7cc97347d0956 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index 5a4a5ced77ca6..1c4b45969fae3 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index bf681e05a1c9b..314fa216d2a1c 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_common.mdx b/api_docs/kbn_content_management_favorites_common.mdx index 59151b09c01d2..0d3aa9f0fb62a 100644 --- a/api_docs/kbn_content_management_favorites_common.mdx +++ b/api_docs/kbn_content_management_favorites_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-common title: "@kbn/content-management-favorites-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-common'] --- import kbnContentManagementFavoritesCommonObj from './kbn_content_management_favorites_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index 7f7c70ed5a6e0..7e40607b21faa 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index bd647fd7e0e62..052d931d97f90 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index d43ad03bd35a3..95a87f1b9637e 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index 1ac307edbda47..ade0488c06679 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index 2ff497094fa75..824bf9224c814 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 391e3af27ab49..25ecb50b36872 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index 1884ecbc28c19..f1aaaeba258f8 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 5627cae609b58..658e6502f3e51 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.devdocs.json b/api_docs/kbn_core_analytics_browser.devdocs.json index 2f2c5fc3f3d9f..d9e9918f342d9 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -942,6 +942,10 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1398,6 +1402,14 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 1eeec516f69ab..bb1cb25cb2211 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 fd3a99d551e46..1b61f04d13f19 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 9f25dffe22bb2..bdc4764b131bd 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json index fe50bcb0679dd..f551b259301d1 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -950,6 +950,10 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1406,6 +1410,14 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 0190a156d47a9..6e3572328aa38 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-11-27 +date: 2024-12-03 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 db36f948aab37..55c716c5195cf 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 95982f2f98687..1dc3b7ced43b1 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 2388640396faf..385b70eab1822 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 f11a00223099a..c93e1d6b36b2d 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 1ed6ccb543298..d2eee2647ac04 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 14a45c71070ba..15b69d35fb423 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-11-27 +date: 2024-12-03 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 6f0b65820c633..f4a263b702009 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 a1473175c1155..d11bf0ef25541 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index 0e5abc28c77c9..9e6309e566ad9 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index e38e3787abfe4..e70df86ee3ed8 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 5dcfe6d9d0db9..f4e6af94f0376 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-11-27 +date: 2024-12-03 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 7152cb9865bd5..59b22026793ac 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 6fcdbedfc1ae6..227ed73b3c168 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 ac43916d1cf55..ff91510acfaf3 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 787d727ee582a..6658412504cf0 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-11-27 +date: 2024-12-03 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 339b0a9479c94..6f6f9b67f4714 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-11-27 +date: 2024-12-03 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 88666bb3631c2..a0c45fad5a714 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index ee8eb55b71f78..ae8118d69b160 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 1a96eba31f321..4d87b9bf64a04 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 9a798431c9031..19132ba78af5c 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 79384cad60f5b..3e877454b83cd 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 5ecd6ebdca371..bd98ce434b956 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 7bb1a96e4d16c..6c9eff9988d3c 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index a4f35895af57e..68beb9c6ae3d5 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 6da4e34f7f78d..372cdd0b4ec53 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index 50d5e0ed28bcb..7942915dc5971 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index a6cc0b31a1425..c259b64cbf3fe 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 4904cf29e9e91..90fe4f7840ccd 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 ce5e019e754b4..60fbb36154474 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 f9e5fccb0f2dc..e3a4f3069d9d0 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 6a35aff5e7465..175356815a82f 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-11-27 +date: 2024-12-03 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 1f35cf7a0c225..b2daa0f917604 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-11-27 +date: 2024-12-03 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 0238f0daa64b2..bd55fd32f8990 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 b21294eae2dbe..cfb99447d5ff4 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 7034950f2f956..fa541c8101c46 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 aff2f5b3b13be..6abfb4f6ef16c 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 7709fe868439c..b8f98e965cf07 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-11-27 +date: 2024-12-03 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 2f719c0bc8aff..2a9917b2c125c 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 66980443a4008..dd669241d943d 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 0d14b25b973cd..c9f33864366fc 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 7522275cf3988..2a2f8f06c4a20 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-11-27 +date: 2024-12-03 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 9fd76ba035883..8893dc1cb951f 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 7ff6ff3c73f95..79c5a37393840 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 238adff330638..e99acf6a3e672 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 048ccb52d9c03..96cd751aff25e 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 92056c81fba1c..cb4aca1b40993 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 aad9099586b11..513da81629358 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 f5a2de6afff40..7967bb82da0db 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 0e4800e45065d..0f608a0690c96 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-11-27 +date: 2024-12-03 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 5bab903f3a2b3..7328a307f1252 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-11-27 +date: 2024-12-03 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 aadcf8d651e60..1fa7cfaf1d569 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 5674e3a9b28bf..8209391797eb8 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 f1bbd967b5822..26e88146b34cb 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 0d931d19e81ef..a875baf15e78e 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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_feature_flags_browser.mdx b/api_docs/kbn_core_feature_flags_browser.mdx index d31566525932c..42fa72a883963 100644 --- a/api_docs/kbn_core_feature_flags_browser.mdx +++ b/api_docs/kbn_core_feature_flags_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser title: "@kbn/core-feature-flags-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser'] --- import kbnCoreFeatureFlagsBrowserObj from './kbn_core_feature_flags_browser.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_internal.mdx b/api_docs/kbn_core_feature_flags_browser_internal.mdx index 9c49928d248fa..d217d041e47f8 100644 --- a/api_docs/kbn_core_feature_flags_browser_internal.mdx +++ b/api_docs/kbn_core_feature_flags_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-internal title: "@kbn/core-feature-flags-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-internal'] --- import kbnCoreFeatureFlagsBrowserInternalObj from './kbn_core_feature_flags_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_mocks.mdx b/api_docs/kbn_core_feature_flags_browser_mocks.mdx index f52fb823c02a9..f0e6419529cec 100644 --- a/api_docs/kbn_core_feature_flags_browser_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-mocks title: "@kbn/core-feature-flags-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-mocks'] --- import kbnCoreFeatureFlagsBrowserMocksObj from './kbn_core_feature_flags_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server.mdx b/api_docs/kbn_core_feature_flags_server.mdx index 2d57b959844a0..7407052fffac0 100644 --- a/api_docs/kbn_core_feature_flags_server.mdx +++ b/api_docs/kbn_core_feature_flags_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server title: "@kbn/core-feature-flags-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server'] --- import kbnCoreFeatureFlagsServerObj from './kbn_core_feature_flags_server.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_internal.mdx b/api_docs/kbn_core_feature_flags_server_internal.mdx index 70807336d2125..8de24625d29c5 100644 --- a/api_docs/kbn_core_feature_flags_server_internal.mdx +++ b/api_docs/kbn_core_feature_flags_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-internal title: "@kbn/core-feature-flags-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-internal'] --- import kbnCoreFeatureFlagsServerInternalObj from './kbn_core_feature_flags_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_mocks.mdx b/api_docs/kbn_core_feature_flags_server_mocks.mdx index 5b3738a90fdc4..8e1c60b0e1223 100644 --- a/api_docs/kbn_core_feature_flags_server_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-mocks title: "@kbn/core-feature-flags-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-mocks'] --- import kbnCoreFeatureFlagsServerMocksObj from './kbn_core_feature_flags_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 6a07b63827076..4f05da87b338f 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 665ed8b94ec89..76025554376d3 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 e112403c1d012..2ed6505492725 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 ad5469dcf96ad..76e5bf1c26146 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-11-27 +date: 2024-12-03 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 68fc3506b7b9c..e5f33881d9b3d 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 a471616c262fc..f4855ca0d6167 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-11-27 +date: 2024-12-03 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 c32bc53646108..1997e4cc5eecc 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-11-27 +date: 2024-12-03 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 f9c521669f3d0..efbdec67cab4d 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 0b7301130451a..c852a9402ddf3 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 ee122c4c2e06d..cbeafe319ddc0 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 126353417814c..2b867d2b8ad3a 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index 9516368c46188..e00fe9fba4edb 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -5453,6 +5453,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/find.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/find.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get.test.ts" @@ -5493,6 +5501,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts" @@ -5549,6 +5565,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/health.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/health.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts" @@ -6755,6 +6779,10 @@ "plugin": "indexManagement", "path": "x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts" }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts" + }, { "plugin": "indexManagement", "path": "x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts" @@ -7447,6 +7475,10 @@ "plugin": "serverlessSearch", "path": "x-pack/plugins/serverless_search/server/routes/connectors_routes.ts" }, + { + "plugin": "serverlessSearch", + "path": "x-pack/plugins/serverless_search/server/routes/connectors_routes.ts" + }, { "plugin": "snapshotRestore", "path": "x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts" @@ -7871,6 +7903,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/create.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/create.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/disable.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/disable.test.ts" @@ -7903,6 +7943,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/enable.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/enable.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts" @@ -7935,6 +7983,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts" @@ -7967,6 +8023,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts" @@ -9125,6 +9189,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/update.test.ts" + }, { "plugin": "remoteClusters", "path": "x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts" @@ -10009,6 +10077,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/delete.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/delete.test.ts" + }, { "plugin": "remoteClusters", "path": "x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts" @@ -17591,6 +17663,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install_translated.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts" @@ -17683,10 +17763,6 @@ "plugin": "dataUsage", "path": "x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stats.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 239099e78e3e4..b708669c2e294 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-11-27 +date: 2024-12-03 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 0564d9ab4a9a9..d65f99fef2e36 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 4c3ebdee17062..d1ad90e098d70 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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_http_server_utils.mdx b/api_docs/kbn_core_http_server_utils.mdx index e313eee198480..6633aca139c15 100644 --- a/api_docs/kbn_core_http_server_utils.mdx +++ b/api_docs/kbn_core_http_server_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-utils title: "@kbn/core-http-server-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-utils'] --- import kbnCoreHttpServerUtilsObj from './kbn_core_http_server_utils.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 0d6c36b44a7f4..5567e2a5af4c6 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 c39a08846f15d..6cfea71eaffbd 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 306d4fa9ebe41..d743f16279ba3 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-11-27 +date: 2024-12-03 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 659f9c3d74dcd..7adde615137c0 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 17a98c73cf292..0ac752131d67a 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 593dd6891aa0a..d8926d7c3e3f8 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 316028c8b3475..8f9c96d1b0820 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 69e82a4bbc3bb..e8c551ba6970c 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 b8c59dc35c208..2e3e60c740e8f 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 b30ba4b039b2d..2b98c841824ba 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index cdb6b5da2b3d2..81363e2d8c60e 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index f72731a886cb2..1efc5ce8cec4a 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 9de8fc0c7b14e..6be2aa265a4a3 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index c71e0fa3c3015..b461602b7cf9c 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 8d53a39d2a617..267c8ca7ec069 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-11-27 +date: 2024-12-03 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 59b629aeca267..dd391bef61679 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 bb250ec74f0b2..2c1d89369c266 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 e601df24b8e72..e92dbb42156e9 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 6ef3603ed8afd..7467c3c278ff9 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 cf48210c4b37b..f97db3c3c112a 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-11-27 +date: 2024-12-03 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 081472bd8efac..1091e8d8ae9ff 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 9211bcbcdb7dd..0b2667b4756aa 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 3a4321119a710..97030cbe9deed 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 92260da937513..aef8e3db6898f 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-11-27 +date: 2024-12-03 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 f1dbaa0cf83d2..0159d8b222d29 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 6fc19b9500365..ca934e7d7fc9f 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 8462d44aca38a..53e4db7c561b8 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 410edf5d9584b..b2e1537228ccf 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 27fb4a22e7404..23c2274e15a38 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 c587cc505939f..50ac9d4b57cc5 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 0cbe0109fc77b..d07a99390dc31 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 ff64b1619758f..75124a902a562 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 4666bd2647990..783da4ddb53f0 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 ccf33372eb4f9..f92668accf930 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index af25fa0a028e8..3443582ec645b 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index fdc7fe938bb71..cafbdd0dbdfea 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 6678b81ceb1b0..21b9b4a11bd16 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 27320d9aa9459..d1ddd23bcebac 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index b50ae1cd81a88..d967299d7f003 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-11-27 +date: 2024-12-03 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 062a3ff6fd922..6651f38621fbc 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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.mdx b/api_docs/kbn_core_rendering_browser.mdx index d61ebee00db9d..40bc8f495cf72 100644 --- a/api_docs/kbn_core_rendering_browser.mdx +++ b/api_docs/kbn_core_rendering_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser title: "@kbn/core-rendering-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser'] --- import kbnCoreRenderingBrowserObj from './kbn_core_rendering_browser.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index d2debc13d0465..45b2d207b2523 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 3a30296295e73..67d55f3ecc1f5 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 f8f6926a33c58..d0577d2523b33 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index f199a6e6c8294..d9714266c585a 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 82ba26e323407..f3cbde1178c1a 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 01868b1e38890..f678ab1ec3d67 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 9594245c7811d..493afd439a826 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 6898e013dab85..aba0c61c2614d 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 b592c67f50317..d9ca3c27db3d2 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 0ccf6a299d194..75f59d3536485 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 ddea6c22ff8a3..68a5fee7c6902 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 e081b8d9cbc62..e615bec13081b 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 202ba38c6ac07..4af0177f5296d 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-11-27 +date: 2024-12-03 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 f88dffe5868cb..22704341fa3f5 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 bea8fb406bd2f..5137325e5f25a 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 6a23ec04fcd0d..9c1431826cd1e 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 7649a00fe6e36..43b6f9c7ca40c 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index b64f85ca1c4e5..ba262035a1c0f 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -10539,7 +10539,7 @@ ], "label": "migrations", "description": [ - "\nAn optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of {@link SavedObjectMigrationFn | migrations} to be used to migrate the type." + "\nAn optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of\n{@link SavedObjectMigrationFn | migrations} to be used to migrate the type.\n" ], "signature": [ { @@ -11445,7 +11445,7 @@ ], "label": "convertToMultiNamespaceTypeVersion", "description": [ - "\nIf defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to this\nversion.\n\nRequirements:\n\n 1. This string value must be a valid semver version\n 2. This type must have previously specified {@link SavedObjectsNamespaceType | `namespaceType: 'single'`}\n 3. This type must also specify {@link SavedObjectsNamespaceType | `namespaceType: 'multiple'`} *or*\n {@link SavedObjectsNamespaceType | `namespaceType: 'multiple-isolated'`}\n\nExample of a single-namespace type in 7.12:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'single',\n mappings: {...}\n}\n```\n\nExample after converting to a multi-namespace (isolated) type in 8.0:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple-isolated',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nExample after converting to a multi-namespace (shareable) type in 8.1:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nNote: migration function(s) can be optionally specified for any of these versions and will not interfere with the conversion process." + "\nIf defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to\nthis version.\n\nRequirements:\n\n 1. This string value must be a valid semver version\n 2. This type must have previously specified {@link SavedObjectsNamespaceType | `namespaceType: 'single'`}\n 3. This type must also specify {@link SavedObjectsNamespaceType | `namespaceType: 'multiple'`} *or*\n {@link SavedObjectsNamespaceType | `namespaceType: 'multiple-isolated'`}\n\nExample of a single-namespace type in 7.12:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'single',\n mappings: {...}\n}\n```\n\nExample after converting to a multi-namespace (isolated) type in 8.0:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple-isolated',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nExample after converting to a multi-namespace (shareable) type in 8.1:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nNote: migration function(s) can be optionally specified for any of these versions and will not interfere with the conversion process." ], "signature": [ "string | undefined" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index ff1eb106d137b..fb9b79f4816e4 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-11-27 +date: 2024-12-03 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 21b61542be92e..017493d5617a9 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 0f6798c4a2afe..9659a6fe1e225 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 9307dd068defa..ae7cb4a7add0a 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-11-27 +date: 2024-12-03 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_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 7f24b84f2b926..08620be021693 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index 2e36aee8e1952..6361b016784ad 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index 9dbe6ae100911..624b0a5d0b129 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index ad0c8529f05d6..386ddb30bdac1 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 7f06c5f69241e..b2215891233ae 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index 034de6ab8fb41..a644a1c8d4081 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index 6a5b45bd34633..b8afb11f52fa7 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 7bf3a446303ea..e1475a8b1af0d 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-11-27 +date: 2024-12-03 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_server.mdx b/api_docs/kbn_core_status_server.mdx index 719068578bdb8..3ffe739dcf1a3 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-11-27 +date: 2024-12-03 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 12dcbf1735c49..2d0c5252744ca 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 9b25f4b831206..f5b5471a7cbfc 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 e0a5f683b381f..21176f25ee98a 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-11-27 +date: 2024-12-03 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 d3d8d23a1c3ec..affb67dfd35a9 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 6dc30092bd529..e1e74dd173f0f 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index 3a4dfd899b209..4ae54cd255a13 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 8cdc827700a0c..b7360eaa5643d 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-11-27 +date: 2024-12-03 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 b33771c2de73a..ef14e3924099c 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 dba0ae243dfd1..90c38d173feca 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 456bc7ca4fa88..6a69407ce5f0a 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 341ee34efa7a1..ec4e3e5b92bf7 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-11-27 +date: 2024-12-03 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 8f8e7c1283964..1a262c962c2c3 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 3f4b908a3df94..a7ee3280341a7 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 e6a99fd108607..37d3a023d3fc3 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-11-27 +date: 2024-12-03 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 29eed144d6bd4..5ca0c3bf77fee 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-11-27 +date: 2024-12-03 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 81444ccc7e48f..4cad5e0861586 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 39cb649f9484c..d103bb0c7d6fd 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 2b88b9802f2a4..fdfe693586930 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-11-27 +date: 2024-12-03 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 2061b9f90d446..cb8a524ee13c5 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 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 c36395eb7bd23..0d4fae499ec4e 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index c571491df9c85..c1fcd5b094ccc 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index 45a139746def3..bef6c0ea9803e 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index 19da2179f5e80..4d890925ee072 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index ad400478d3b63..b39634e1c9b6a 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index 8d54e31eeec9f..2c02b4fa2e39f 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index 95692d637afc3..198f309fb2a69 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index a31ffdf34f730..c3fc8a4dca169 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index 8f229a447b015..7c4f2b3a3f3d0 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index f4f872d529e1d..a33bf4c57ffed 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 3c9c846f4479e..3cb164f04dcb3 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-11-27 +date: 2024-12-03 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 a99e2bc2886a7..d1979d3093040 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index ef0d98e2017e0..af91c339c9053 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 94bab9c726502..8655a577dea72 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index d966d94e2f1ea..3f621be4e2203 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index 610d57492184f..2a3339618636f 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 640c9c3f0fc39..6551b2268ad04 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index 17984c33dae81..ebb7346d96d6d 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index 2748d31c63042..79a9c2dbb7b0d 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 29c6b2ff1f68e..1455bf677aff7 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index c6e81a90bb307..b65be683d9a4c 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index 0b462e13098e3..54539c3301c12 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index 0679b51ff2ebe..d3b9bb051e83e 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 32b19162bb750..7ae3d99853bde 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 0f9a0526365e3..a6b5fa3abb5b7 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 7ed44839f8121..af6d377e013d9 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 56da3daa9299d..1a2a2cd9ef0ce 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index 346814df331a9..c54c298706262 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index 400a090bcc3cc..1539a457301ec 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index e3f34cf1c5f66..a504eacb588bf 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 981dd42507535..d3b5f84e66789 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 92c8985e6ff06..c3a20a08c0dd5 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 731b84ca0eb2b..f24a7c9a93bf8 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 67d3d790ae176..54aa8ae5d2c5c 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-11-27 +date: 2024-12-03 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 7884aa106ad3e..3883f9059ea02 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-11-27 +date: 2024-12-03 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 e759dd7d8b8ce..2701e447f13f2 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-11-27 +date: 2024-12-03 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 1be3293687b7f..c20cd17c10d5d 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_contextual_components.mdx b/api_docs/kbn_discover_contextual_components.mdx index 66c962ab966ed..399c8f63e9e85 100644 --- a/api_docs/kbn_discover_contextual_components.mdx +++ b/api_docs/kbn_discover_contextual_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-contextual-components title: "@kbn/discover-contextual-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-contextual-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-contextual-components'] --- import kbnDiscoverContextualComponentsObj from './kbn_discover_contextual_components.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index e7b74c9967595..575c61a63f7bc 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 2c3281ac89a96..eb3ea0aa8619c 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -669,7 +669,7 @@ "label": "alerting", "description": [], "signature": [ - "{ readonly guide: string; readonly actionTypes: string; readonly apmRulesErrorCount: string; readonly apmRulesTransactionDuration: string; readonly apmRulesTransactionError: string; readonly apmRulesAnomaly: string; readonly emailAction: string; readonly emailActionConfig: string; readonly emailExchangeClientSecretConfig: string; readonly emailExchangeClientIdConfig: string; readonly generalSettings: string; readonly indexAction: string; readonly esQuery: string; readonly indexThreshold: string; readonly maintenanceWindows: string; readonly pagerDutyAction: string; readonly preconfiguredConnectors: string; readonly preconfiguredAlertHistoryConnector: string; readonly serviceNowAction: string; readonly serviceNowSIRAction: string; readonly setupPrerequisites: string; readonly slackAction: string; readonly slackApiAction: string; readonly teamsAction: string; readonly connectors: string; }" + "{ readonly guide: string; readonly actionTypes: string; readonly apmRulesErrorCount: string; readonly apmRulesTransactionDuration: string; readonly apmRulesTransactionError: string; readonly apmRulesAnomaly: string; readonly emailAction: string; readonly emailActionConfig: string; readonly emailExchangeClientSecretConfig: string; readonly emailExchangeClientIdConfig: string; readonly generalSettings: string; readonly indexAction: string; readonly esQuery: string; readonly indexThreshold: string; readonly maintenanceWindows: string; readonly pagerDutyAction: string; readonly preconfiguredConnectors: string; readonly preconfiguredAlertHistoryConnector: string; readonly serviceNowAction: string; readonly serviceNowSIRAction: string; readonly setupPrerequisites: string; readonly slackAction: string; readonly slackApiAction: string; readonly teamsAction: string; readonly connectors: string; readonly legacyRuleApiDeprecations: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -1038,6 +1038,20 @@ "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/doc-links", + "id": "def-common.DocLinks.cases", + "type": "Object", + "tags": [], + "label": "cases", + "description": [], + "signature": [ + "{ readonly legacyApiDeprecations: string; }" + ], + "path": "packages/kbn-doc-links/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 5edac051e34f9..35e2126df6ab7 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/docs](https://github.com/orgs/elastic/teams/docs) for question | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 79 | 0 | 79 | 2 | +| 80 | 0 | 80 | 2 | ## Common diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 2529617678be2..c986a79cd2119 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 23c00490f2002..b8416c3ddc464 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 31a540ac5ef43..1c566e0da9228 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 12c6e32d5e464..db839b71d28b8 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index 1a3123ba92ee7..f9337eea4a0ef 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.devdocs.json b/api_docs/kbn_elastic_assistant.devdocs.json index e6e5d9a8e9619..f4e458bb3a3b2 100644 --- a/api_docs/kbn_elastic_assistant.devdocs.json +++ b/api_docs/kbn_elastic_assistant.devdocs.json @@ -2587,6 +2587,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant", + "id": "def-public.DEFEND_INSIGHTS_STORAGE_KEY", + "type": "string", + "tags": [], + "label": "DEFEND_INSIGHTS_STORAGE_KEY", + "description": [], + "signature": [ + "\"defendInsights\"" + ], + "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant", "id": "def-public.ELASTIC_AI_ASSISTANT_TITLE", diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 29f0d21808458..96a0ddcc59cf9 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 169 | 0 | 140 | 10 | +| 170 | 0 | 141 | 10 | ## Client diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 5a7c80267455c..7d8c4aca6ae58 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.devdocs.json b/api_docs/kbn_entities_schema.devdocs.json index 5bc7ba4f31a9f..0269efb5711d8 100644 --- a/api_docs/kbn_entities_schema.devdocs.json +++ b/api_docs/kbn_entities_schema.devdocs.json @@ -144,10 +144,10 @@ }, { "parentPluginId": "@kbn/entities-schema", - "id": "def-common.EntityV2.entity.last_seen_timestamp", + "id": "def-common.EntityV2.entity.type", "type": "string", "tags": [], - "label": "'entity.last_seen_timestamp'", + "label": "'entity.type'", "description": [], "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", "deprecated": false, @@ -155,15 +155,29 @@ }, { "parentPluginId": "@kbn/entities-schema", - "id": "def-common.EntityV2.entity.type", + "id": "def-common.EntityV2.entity.display_name", "type": "string", "tags": [], - "label": "'entity.type'", + "label": "'entity.display_name'", "description": [], "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.entity.last_seen_timestamp", + "type": "string", + "tags": [], + "label": "'entity.last_seen_timestamp'", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/entities-schema", "id": "def-common.EntityV2.Unnamed", diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 6286b02a629ea..44f3602c6853b 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entiti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 50 | 0 | 50 | 0 | +| 51 | 0 | 51 | 0 | ## Common diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 414cac7189286..a5b21a5246807 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 97f2dec280336..08056225d1035 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-11-27 +date: 2024-12-03 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 4f003eb7cfb64..103cdb4662ab2 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-11-27 +date: 2024-12-03 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 9b8eb7fd01482..0a2ccb86bd955 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-11-27 +date: 2024-12-03 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 91906ad301c86..91d3926517788 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-11-27 +date: 2024-12-03 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 a4ed40391bd0b..7d28e5b2815ff 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.devdocs.json b/api_docs/kbn_esql_ast.devdocs.json index 2c8e443f45d05..bf0442c6badd7 100644 --- a/api_docs/kbn_esql_ast.devdocs.json +++ b/api_docs/kbn_esql_ast.devdocs.json @@ -282,13 +282,7 @@ "description": [], "signature": [ "(expression: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ", opts?: ", { "pluginId": "@kbn/esql-ast", @@ -313,13 +307,7 @@ "ES|QL expression AST node to print." ], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -496,13 +484,7 @@ "description": [], "signature": [ "(node: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ", minusCount?: number) => string | undefined" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", @@ -517,13 +499,7 @@ "label": "node", "description": [], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -666,13 +642,7 @@ "description": [], "signature": [ "(expression: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ") => any" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", @@ -687,13 +657,7 @@ "label": "expression", "description": [], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -2142,6 +2106,57 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkInlineCast", + "type": "Function", + "tags": [], + "label": "walkInlineCast", + "description": [], + "signature": [ + "(node: ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + ">) => void" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkInlineCast.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + ">" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.Walker.walkFunction", @@ -2599,13 +2614,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2621,13 +2630,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2645,13 +2648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2667,13 +2664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2693,13 +2684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2715,13 +2700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2739,13 +2718,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2761,13 +2734,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2797,13 +2764,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2819,13 +2780,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2843,13 +2798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2865,13 +2814,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2891,13 +2834,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2913,13 +2850,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2937,13 +2868,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2959,13 +2884,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2997,13 +2916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3019,13 +2932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3043,13 +2950,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3065,13 +2966,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3091,13 +2986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3113,13 +3002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3137,13 +3020,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3159,13 +3036,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3195,13 +3066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3217,13 +3082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3241,13 +3100,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3263,13 +3116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3289,13 +3136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3311,13 +3152,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3335,13 +3170,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3357,13 +3186,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3397,13 +3220,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3419,13 +3236,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3443,13 +3254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3465,13 +3270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3491,13 +3290,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3513,13 +3306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3537,13 +3324,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3559,13 +3340,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3595,13 +3370,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3617,13 +3386,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3641,13 +3404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3663,13 +3420,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3689,13 +3440,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3711,13 +3456,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3735,13 +3474,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3757,13 +3490,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3795,13 +3522,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3817,13 +3538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3841,13 +3556,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3863,13 +3572,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3889,13 +3592,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3911,13 +3608,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3935,13 +3626,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3957,13 +3642,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3993,13 +3672,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4015,13 +3688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4039,13 +3706,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4061,13 +3722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4087,13 +3742,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4109,13 +3758,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4133,13 +3776,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4155,13 +3792,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4197,13 +3828,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4219,13 +3844,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4243,13 +3862,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4265,13 +3878,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4291,13 +3898,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4313,13 +3914,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4337,13 +3932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4359,13 +3948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4395,13 +3978,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4417,13 +3994,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4441,13 +4012,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4463,13 +4028,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4489,13 +4048,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4511,13 +4064,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4535,13 +4082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4557,13 +4098,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4595,13 +4130,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4617,13 +4146,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4641,13 +4164,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4663,13 +4180,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4689,13 +4200,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4711,13 +4216,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4735,13 +4234,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4757,13 +4250,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4793,13 +4280,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4815,13 +4296,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4839,13 +4314,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4861,13 +4330,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4887,13 +4350,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4909,13 +4366,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4933,13 +4384,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4955,13 +4400,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4995,13 +4434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5017,13 +4450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5041,13 +4468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5063,13 +4484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5089,13 +4504,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5111,13 +4520,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5135,13 +4538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5157,13 +4554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5193,13 +4584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5215,13 +4600,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5239,13 +4618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5261,13 +4634,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5287,13 +4654,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5309,13 +4670,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5333,13 +4688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5355,13 +4704,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5393,13 +4736,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5415,13 +4752,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5439,13 +4770,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5461,13 +4786,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5487,13 +4806,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5509,13 +4822,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5533,13 +4840,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5555,13 +4856,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5591,13 +4886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5613,13 +4902,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5637,13 +4920,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5659,13 +4936,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5685,13 +4956,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5707,13 +4972,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5731,13 +4990,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5753,13 +5006,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5799,13 +5046,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5821,13 +5062,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5845,13 +5080,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5867,13 +5096,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5893,13 +5116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5915,13 +5132,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5939,13 +5150,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5961,13 +5166,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5997,13 +5196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6019,13 +5212,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6043,13 +5230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6065,13 +5246,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6091,13 +5266,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6113,13 +5282,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6137,13 +5300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6159,13 +5316,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6197,13 +5348,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6219,13 +5364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6243,13 +5382,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6265,13 +5398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6291,13 +5418,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6313,13 +5434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6337,13 +5452,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6359,13 +5468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6395,13 +5498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6417,13 +5514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6441,13 +5532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6463,13 +5548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6489,13 +5568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6511,13 +5584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6535,13 +5602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6557,13 +5618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6597,13 +5652,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6619,13 +5668,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6643,13 +5686,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6665,13 +5702,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6691,13 +5722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6713,13 +5738,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6737,13 +5756,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6759,13 +5772,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6795,13 +5802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6817,13 +5818,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6841,13 +5836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6863,13 +5852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6889,13 +5872,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6911,13 +5888,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6935,13 +5906,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6957,13 +5922,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6995,13 +5954,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7017,13 +5970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7041,13 +5988,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7063,13 +6004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7089,13 +6024,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7111,13 +6040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7135,13 +6058,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7157,13 +6074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7193,13 +6104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7215,13 +6120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7239,13 +6138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7261,13 +6154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7287,13 +6174,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7309,13 +6190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7333,13 +6208,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7355,13 +6224,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7397,13 +6260,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7419,13 +6276,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7443,13 +6294,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7465,13 +6310,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7491,13 +6330,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7513,13 +6346,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7537,13 +6364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7559,13 +6380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7595,13 +6410,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7617,13 +6426,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7641,13 +6444,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7663,13 +6460,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7689,13 +6480,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7711,13 +6496,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7735,13 +6514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7757,13 +6530,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7795,13 +6562,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7817,13 +6578,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7841,13 +6596,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7863,13 +6612,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7889,13 +6632,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7911,13 +6648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7935,13 +6666,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7957,13 +6682,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7993,13 +6712,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8015,13 +6728,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8039,13 +6746,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8061,13 +6762,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8087,13 +6782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8109,13 +6798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8133,13 +6816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8155,13 +6832,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8195,13 +6866,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8217,13 +6882,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8241,13 +6900,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8263,13 +6916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8289,13 +6936,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8311,13 +6952,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8335,13 +6970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8357,13 +6986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8393,13 +7016,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8415,13 +7032,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8439,13 +7050,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8461,13 +7066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8487,13 +7086,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8509,13 +7102,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8533,13 +7120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8555,13 +7136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8593,13 +7168,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8615,13 +7184,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8639,13 +7202,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8661,13 +7218,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8687,13 +7238,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8709,13 +7254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8733,13 +7272,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8755,13 +7288,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8791,13 +7318,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8813,13 +7334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8837,13 +7352,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8859,13 +7368,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8885,13 +7388,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8907,13 +7404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8931,13 +7422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8953,13 +7438,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9001,13 +7480,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9023,13 +7496,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9047,13 +7514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9069,13 +7530,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9095,13 +7550,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9117,13 +7566,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9141,13 +7584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9163,13 +7600,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9199,13 +7630,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9221,13 +7646,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9245,13 +7664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9267,13 +7680,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9293,13 +7700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9315,13 +7716,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9339,13 +7734,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9361,13 +7750,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9399,13 +7782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9421,13 +7798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9445,13 +7816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9467,13 +7832,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9493,13 +7852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9515,13 +7868,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9539,13 +7886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9561,13 +7902,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9597,13 +7932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9619,13 +7948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9643,13 +7966,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9665,13 +7982,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9691,13 +8002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9713,13 +8018,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9737,13 +8036,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9759,13 +8052,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9799,13 +8086,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9821,13 +8102,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9845,13 +8120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9867,13 +8136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9893,13 +8156,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9915,13 +8172,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9939,13 +8190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9961,13 +8206,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9997,13 +8236,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10019,13 +8252,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10043,13 +8270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10065,13 +8286,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10091,13 +8306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10113,13 +8322,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10137,13 +8340,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10159,13 +8356,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10197,13 +8388,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10219,13 +8404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10243,13 +8422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10265,13 +8438,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10291,13 +8458,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10313,13 +8474,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10337,13 +8492,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10359,13 +8508,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10395,13 +8538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10417,13 +8554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10441,13 +8572,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10463,13 +8588,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10489,13 +8608,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10511,13 +8624,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10535,13 +8642,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10557,13 +8658,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10599,13 +8694,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10621,13 +8710,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10645,13 +8728,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10667,13 +8744,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10693,13 +8764,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10715,13 +8780,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10739,13 +8798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10761,13 +8814,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10797,13 +8844,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10819,13 +8860,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10843,13 +8878,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10865,13 +8894,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10891,13 +8914,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10913,13 +8930,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10937,13 +8948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10959,13 +8964,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10997,13 +8996,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11019,13 +9012,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11043,13 +9030,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11065,13 +9046,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11091,13 +9066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11113,13 +9082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11137,13 +9100,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11159,13 +9116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11195,13 +9146,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11217,13 +9162,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11241,13 +9180,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11263,13 +9196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11289,13 +9216,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11311,13 +9232,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11335,13 +9250,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11357,13 +9266,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11397,13 +9300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11419,13 +9316,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11443,13 +9334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11465,13 +9350,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11491,13 +9370,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11513,13 +9386,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11537,13 +9404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11559,13 +9420,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11595,13 +9450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11617,13 +9466,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11641,13 +9484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11663,13 +9500,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11689,13 +9520,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11711,13 +9536,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11735,13 +9554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11757,13 +9570,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11795,13 +9602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11817,13 +9618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11841,13 +9636,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11863,13 +9652,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11889,13 +9672,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11911,13 +9688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11935,13 +9706,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11957,13 +9722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11993,13 +9752,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12015,13 +9768,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12039,13 +9786,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12061,13 +9802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12087,13 +9822,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12109,13 +9838,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12133,13 +9856,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12155,13 +9872,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12201,13 +9912,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12223,13 +9928,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12247,13 +9946,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12269,13 +9962,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12295,13 +9982,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12317,13 +9998,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12341,13 +10016,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12363,13 +10032,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12399,13 +10062,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12421,13 +10078,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12445,13 +10096,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12467,13 +10112,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12493,13 +10132,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12515,13 +10148,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12539,13 +10166,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12561,13 +10182,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12599,13 +10214,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12621,13 +10230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12645,13 +10248,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12667,13 +10264,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12693,13 +10284,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12715,13 +10300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12739,13 +10318,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12761,13 +10334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12797,13 +10364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12819,13 +10380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12843,13 +10398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12865,13 +10414,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12891,13 +10434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12913,13 +10450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12937,13 +10468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12959,13 +10484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12999,13 +10518,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13021,13 +10534,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13045,13 +10552,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13067,13 +10568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13093,13 +10588,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13115,13 +10604,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13139,13 +10622,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13161,13 +10638,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13197,13 +10668,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13219,13 +10684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13243,13 +10702,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13265,13 +10718,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13291,13 +10738,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13313,13 +10754,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13337,13 +10772,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13359,13 +10788,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13397,13 +10820,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13419,13 +10836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13443,13 +10854,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13465,13 +10870,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13491,13 +10890,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13513,13 +10906,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13537,13 +10924,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13559,13 +10940,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13595,13 +10970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13617,13 +10986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13641,13 +11004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13663,13 +11020,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13689,13 +11040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13711,13 +11056,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13735,13 +11074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13757,13 +11090,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13799,13 +11126,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13821,13 +11142,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13845,13 +11160,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13867,13 +11176,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13893,13 +11196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13915,13 +11212,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13939,13 +11230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13961,13 +11246,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13997,13 +11276,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14019,13 +11292,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14043,13 +11310,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14065,13 +11326,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14091,13 +11346,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14113,13 +11362,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14137,13 +11380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14159,13 +11396,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14197,13 +11428,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14219,13 +11444,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14243,13 +11462,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14265,13 +11478,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14291,13 +11498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14313,13 +11514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14337,13 +11532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14359,13 +11548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14395,13 +11578,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14417,13 +11594,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14441,13 +11612,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14463,13 +11628,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14489,13 +11648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14511,13 +11664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14535,13 +11682,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14557,13 +11698,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14597,13 +11732,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14619,13 +11748,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14643,13 +11766,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14665,13 +11782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14691,13 +11802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14713,13 +11818,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14737,13 +11836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14759,13 +11852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14795,13 +11882,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14817,13 +11898,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14841,13 +11916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14863,13 +11932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14889,13 +11952,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14911,13 +11968,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14935,13 +11986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14957,13 +12002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14991,17 +12030,11 @@ "<", "VisitorMethods", ", ", - "SharedData", - ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "SharedData", + ">, ", + "SharedData", + ", ", + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15017,13 +12050,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15041,13 +12068,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15063,13 +12084,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15089,13 +12104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15111,13 +12120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15135,13 +12138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15157,13 +12154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15193,13 +12184,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15215,13 +12200,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15239,13 +12218,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15261,13 +12234,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15287,13 +12254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15309,13 +12270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15333,13 +12288,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15355,13 +12304,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15405,13 +12348,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15427,13 +12364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15451,13 +12382,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15473,13 +12398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15499,13 +12418,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15521,13 +12434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15545,13 +12452,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15567,13 +12468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15603,13 +12498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15625,13 +12514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15649,13 +12532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15671,13 +12548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15697,13 +12568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15719,13 +12584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15743,13 +12602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15765,13 +12618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15803,13 +12650,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15825,13 +12666,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15849,13 +12684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15871,13 +12700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15897,13 +12720,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15919,13 +12736,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15943,13 +12754,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15965,13 +12770,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16001,13 +12800,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16023,13 +12816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16047,13 +12834,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16069,13 +12850,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16095,13 +12870,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16117,13 +12886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16141,13 +12904,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16163,13 +12920,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16203,13 +12954,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16225,13 +12970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16249,13 +12988,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16271,13 +13004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16297,13 +13024,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16319,13 +13040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16343,13 +13058,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16365,13 +13074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16401,13 +13104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16423,13 +13120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16447,13 +13138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16469,13 +13154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16495,13 +13174,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16517,13 +13190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16541,13 +13208,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16563,13 +13224,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16601,13 +13256,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16623,13 +13272,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16647,13 +13290,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16669,13 +13306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16695,13 +13326,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16717,13 +13342,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16741,13 +13360,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16763,13 +13376,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16799,13 +13406,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16821,13 +13422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { ...; } & { ...; }, ", @@ -18521,18 +15116,6 @@ { "plugin": "@kbn/esql-utils", "path": "packages/kbn-esql-utils/src/utils/append_to_query.ts" - }, - { - "plugin": "@kbn/securitysolution-utils", - "path": "packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts" } ] }, @@ -19909,6 +16492,40 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.identifier", + "type": "Function", + "tags": [], + "label": "identifier", + "description": [], + "signature": [ + "(node: ", + "ESQLIdentifier", + ") => string" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.identifier.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLIdentifier" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.LeafPrinter.column", @@ -20162,6 +16779,40 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.print", + "type": "Function", + "tags": [], + "label": "print", + "description": [], + "signature": [ + "(node: ", + "ESQLProperNode", + ") => string" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.print.$1", + "type": "CompoundType", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLProperNode" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index c72e95cb80f6d..4a5f0a3e7bec0 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 277 | 1 | 216 | 36 | +| 283 | 1 | 222 | 36 | ## Common diff --git a/api_docs/kbn_esql_editor.mdx b/api_docs/kbn_esql_editor.mdx index b1e91675954f7..e248e4ea11ebb 100644 --- a/api_docs/kbn_esql_editor.mdx +++ b/api_docs/kbn_esql_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-editor title: "@kbn/esql-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-editor plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-editor'] --- import kbnEsqlEditorObj from './kbn_esql_editor.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 29ed84eed3f3d..b0514fa934b3f 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 879e9e1203f25..88c2ac9e48182 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 3a1b4a94208d2..87e1d520171bc 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 304073cf3b7fb..c19339435c2a2 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.devdocs.json b/api_docs/kbn_expandable_flyout.devdocs.json index 8224ebb0e15ac..10de89b7d3657 100644 --- a/api_docs/kbn_expandable_flyout.devdocs.json +++ b/api_docs/kbn_expandable_flyout.devdocs.json @@ -138,57 +138,6 @@ "children": [], "returnComment": [], "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider", - "type": "Function", - "tags": [], - "label": "withExpandableFlyoutProvider", - "description": [], - "signature": [ - "(Component: React.ComponentType, expandableProviderProps?: ", - "ExpandableFlyoutContextProviderProps", - " | undefined) => (props: Props) => React.JSX.Element" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider.$1", - "type": "CompoundType", - "tags": [], - "label": "Component", - "description": [], - "signature": [ - "React.ComponentType" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider.$2", - "type": "Object", - "tags": [], - "label": "expandableProviderProps", - "description": [], - "signature": [ - "ExpandableFlyoutContextProviderProps", - " | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false } ], "interfaces": [ diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index b7ec3a1fa4a7a..9000c27e42bba 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 44 | 0 | 17 | 3 | +| 41 | 0 | 14 | 2 | ## Client diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index f1485e842844a..918a1fcb1ab0b 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 58d389df7c179..ffc55a9cb0d60 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 97cf5c8b17c68..d735227da336a 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-11-27 +date: 2024-12-03 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_formatters.mdx b/api_docs/kbn_formatters.mdx index c176e3c2c0f8b..28d8b3a1038a2 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 4055e3be66d18..dc63d68701864 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index b2d8b3422bcd2..0265a519eb55a 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 84eba92f94ac0..257c25cd2d4a3 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 470d9cff000a4..c5dc8ad3d6c02 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index ac73e8ddb0aa7..a607f6fda20b6 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.devdocs.json b/api_docs/kbn_grid_layout.devdocs.json index acd664c6cac81..411b0d387d6e4 100644 --- a/api_docs/kbn_grid_layout.devdocs.json +++ b/api_docs/kbn_grid_layout.devdocs.json @@ -11,7 +11,7 @@ "label": "GridLayout", "description": [], "signature": [ - "({ layout, gridSettings, renderPanelContents, onLayoutChange, }: GridLayoutProps) => React.JSX.Element" + "({ layout, gridSettings, renderPanelContents, onLayoutChange, expandedPanelId, accessMode, }: GridLayoutProps) => React.JSX.Element" ], "path": "packages/kbn-grid-layout/grid/grid_layout.tsx", "deprecated": false, @@ -22,7 +22,7 @@ "id": "def-public.GridLayout.$1", "type": "Object", "tags": [], - "label": "{\n layout,\n gridSettings,\n renderPanelContents,\n onLayoutChange,\n}", + "label": "{\n layout,\n gridSettings,\n renderPanelContents,\n onLayoutChange,\n expandedPanelId,\n accessMode = 'EDIT',\n}", "description": [], "signature": [ "GridLayoutProps" @@ -258,6 +258,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/grid-layout", + "id": "def-public.GridAccessMode", + "type": "Type", + "tags": [], + "label": "GridAccessMode", + "description": [], + "signature": [ + "\"VIEW\" | \"EDIT\"" + ], + "path": "packages/kbn-grid-layout/grid/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/grid-layout", "id": "def-public.GridLayoutData", diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index f443631ecffb1..3b5b2d38d288d 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 16 | 1 | +| 17 | 0 | 17 | 1 | ## Client diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index ec32fdbb3dc39..0afb988a87149 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index e04edf3fa2f1e..07ab2aac3453d 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-11-27 +date: 2024-12-03 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 4f829c2becee1..b0f23a50a30b6 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-11-27 +date: 2024-12-03 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 607539b03fc8e..47a3a083c8eff 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 060cb90d60408..1960482ce1873 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 5c0763e8a832c..6f993df67f97b 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-11-27 +date: 2024-12-03 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 c0fae18ef938d..85a33135ef8af 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-11-27 +date: 2024-12-03 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 256d2057dc2ab..7e04c4bc64410 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 26aa9eaeec20a..3a1018ad2270e 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 8c05bbdab24a6..6ef15ebfbb5d6 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_adapter.mdx b/api_docs/kbn_index_adapter.mdx index 3c9e5b7de118a..d879aa0fd368d 100644 --- a/api_docs/kbn_index_adapter.mdx +++ b/api_docs/kbn_index_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-adapter title: "@kbn/index-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-adapter plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-adapter'] --- import kbnIndexAdapterObj from './kbn_index_adapter.devdocs.json'; diff --git a/api_docs/kbn_index_lifecycle_management_common_shared.mdx b/api_docs/kbn_index_lifecycle_management_common_shared.mdx index d7db0564df5b2..f1dde434829d9 100644 --- a/api_docs/kbn_index_lifecycle_management_common_shared.mdx +++ b/api_docs/kbn_index_lifecycle_management_common_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-lifecycle-management-common-shared title: "@kbn/index-lifecycle-management-common-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-lifecycle-management-common-shared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-lifecycle-management-common-shared'] --- import kbnIndexLifecycleManagementCommonSharedObj from './kbn_index_lifecycle_management_common_shared.devdocs.json'; diff --git a/api_docs/kbn_index_management_shared_types.mdx b/api_docs/kbn_index_management_shared_types.mdx index 621e5614f6dea..245bfbb2b8883 100644 --- a/api_docs/kbn_index_management_shared_types.mdx +++ b/api_docs/kbn_index_management_shared_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management-shared-types title: "@kbn/index-management-shared-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management-shared-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management-shared-types'] --- import kbnIndexManagementSharedTypesObj from './kbn_index_management_shared_types.devdocs.json'; diff --git a/api_docs/kbn_inference_common.mdx b/api_docs/kbn_inference_common.mdx index 44631b34523cb..94da9c77efb54 100644 --- a/api_docs/kbn_inference_common.mdx +++ b/api_docs/kbn_inference_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference-common title: "@kbn/inference-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference-common'] --- import kbnInferenceCommonObj from './kbn_inference_common.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 51dfdb94c246d..afbe1bbccd177 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index f8b44436588b1..37563b02dbf1c 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 24989e420f9e4..a1cf8e0625a76 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index c5e39a67d67bb..e15da2052ee4f 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index da60e53c2b889..7b4d6cb76c62c 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index 00e1a0b19c50c..db11da137ee74 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_item_buffer.mdx b/api_docs/kbn_item_buffer.mdx index cfdf3841d304a..2271ae79bfd84 100644 --- a/api_docs/kbn_item_buffer.mdx +++ b/api_docs/kbn_item_buffer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-item-buffer title: "@kbn/item-buffer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/item-buffer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/item-buffer'] --- import kbnItemBufferObj from './kbn_item_buffer.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 7865658ddcce2..313c3d90e615c 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-11-27 +date: 2024-12-03 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 19cc3c9f3a933..cb52b76f3e656 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 9526c458afa3a..0bc116461cd9f 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index 3db66f4da6bc5..76f1da98e7202 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 86902f77b518f..5b12795dee994 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-11-27 +date: 2024-12-03 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.mdx b/api_docs/kbn_language_documentation.mdx index e781d7cea0c8a..b73082cc05537 100644 --- a/api_docs/kbn_language_documentation.mdx +++ b/api_docs/kbn_language_documentation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation title: "@kbn/language-documentation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation'] --- import kbnLanguageDocumentationObj from './kbn_language_documentation.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 21999e304ba40..4b939509b4c1b 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 74cef7b6a14c5..7112c1008157e 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 1b03e3046a11c..8fb3be8864c78 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-11-27 +date: 2024-12-03 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 a32690b53564b..837ac4721ebce 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index bb21763f25ea2..dde5ec6d1a50e 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index b7a75c874067b..55eea305678c4 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index 00035f9dcbaa8..2db4f527e160e 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index fc860e51c6e02..5479db788c684 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index 31469ca726295..dc68e598b6d5e 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 70070064f84a1..a1cb7fde56bb7 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index df0ed5992e902..903896f47ab4a 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index ec615e34fd5bb..23f6c111f9358 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index cc4c07ea50f76..775a385a0c4fb 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index fd84ccadcf5cf..68f7d07837e9a 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index d06736eb32165..302b3f5520e86 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index aa66559ec06fa..be056860418a8 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 9346502364794..a0dd4ed2bfaca 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 942d7cbda8bb6..58f02befefd12 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_manifest.mdx b/api_docs/kbn_manifest.mdx index 7665b8e2eeeb1..b4c1a7d344d99 100644 --- a/api_docs/kbn_manifest.mdx +++ b/api_docs/kbn_manifest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-manifest title: "@kbn/manifest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/manifest plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/manifest'] --- import kbnManifestObj from './kbn_manifest.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 2a0e542851cd6..417cef0255309 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index 42999cf9b9942..aa7a2b00efa36 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 0783b2c02cb20..c798d2a14dbf1 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 0d27c25f02fc4..5c04c5bf3c7e8 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index 822a864e6cae3..bccf9871bb700 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 18c232adc51b8..7049fb1c993cb 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index 7c250928de948..c7a672f0a9bf8 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index dbc7137f7e589..a510a28e70f18 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index 1995a4bfb6002..328d8ab43cad0 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index e98156386e950..20ed3d344ff0c 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 4fbc2f8f71382..2ccc1a8d0ca3e 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 4b42c43ce5883..0f14619eea8d5 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_field_stats_flyout.mdx b/api_docs/kbn_ml_field_stats_flyout.mdx index 57e6bdf6f1941..7ca2933d42708 100644 --- a/api_docs/kbn_ml_field_stats_flyout.mdx +++ b/api_docs/kbn_ml_field_stats_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-field-stats-flyout title: "@kbn/ml-field-stats-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-field-stats-flyout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-field-stats-flyout'] --- import kbnMlFieldStatsFlyoutObj from './kbn_ml_field_stats_flyout.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index e05494e8055aa..fca65dac63dcc 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index d156a38390dd7..67d0e11795de5 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 25605198a53b7..eb3713848a0b7 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 6c8d55c988991..0432c75446ce3 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 0e60eea84be75..0c03b4334e57e 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 253cf6ad7af09..383213651c64b 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 3dd900c8a351b..4e51d1d0009d9 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_parse_interval.mdx b/api_docs/kbn_ml_parse_interval.mdx index bbaf7b3ccfad4..79776bb90c849 100644 --- a/api_docs/kbn_ml_parse_interval.mdx +++ b/api_docs/kbn_ml_parse_interval.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-parse-interval title: "@kbn/ml-parse-interval" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-parse-interval plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-parse-interval'] --- import kbnMlParseIntervalObj from './kbn_ml_parse_interval.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index bc82bc0a0efb4..f70ee2016d1f5 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 5c2b1fc919c6c..41c0612f70e10 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index dec47a9adb1fe..a77f77c57730e 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 447ec64eb51dc..96cac2b534741 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 9d49852f8ff2e..645d4beed457c 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 8cd1f88a5f9fa..fbc302a9d09dd 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 97d2654c93147..817cc7be8687c 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 6d2b86d46e48b..0eeb89193d1b0 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 3bd64539af0cf..dee866819cc94 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_ml_validators.mdx b/api_docs/kbn_ml_validators.mdx index b9b317a414f7b..89da130184b69 100644 --- a/api_docs/kbn_ml_validators.mdx +++ b/api_docs/kbn_ml_validators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-validators title: "@kbn/ml-validators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-validators plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-validators'] --- import kbnMlValidatorsObj from './kbn_ml_validators.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index bd7601966e824..61bab08535a8f 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 5a490123a4070..ed9d2f96307ed 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 93044cb8e4951..c9172a194bb92 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_object_versioning_utils.mdx b/api_docs/kbn_object_versioning_utils.mdx index 590df77595f6b..bcf44cf3f807a 100644 --- a/api_docs/kbn_object_versioning_utils.mdx +++ b/api_docs/kbn_object_versioning_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning-utils title: "@kbn/object-versioning-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning-utils'] --- import kbnObjectVersioningUtilsObj from './kbn_object_versioning_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index b324da2ba4582..78a482ad69844 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index 67b69c0e0ad6c..d50cc46632056 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 0c1d5b2e5d09e..ad1f805afb938 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index 6489039c76e82..0f54b2e88fe49 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_observability_logs_overview.devdocs.json b/api_docs/kbn_observability_logs_overview.devdocs.json index 43156c3b352e4..e43439900367a 100644 --- a/api_docs/kbn_observability_logs_overview.devdocs.json +++ b/api_docs/kbn_observability_logs_overview.devdocs.json @@ -316,6 +316,8 @@ "LogCategoriesGridChangeTimeCellDependencies", " & ", "LogCategoryDocumentExamplesTableDependencies", + " & ", + "DiscoverLinkDependencies", " & { search: ", { "pluginId": "@kbn/search-types", @@ -467,6 +469,8 @@ "LogCategoriesGridChangeTimeCellDependencies", " & ", "LogCategoryDocumentExamplesTableDependencies", + " & ", + "DiscoverLinkDependencies", " & { search: ", { "pluginId": "@kbn/search-types", diff --git a/api_docs/kbn_observability_logs_overview.mdx b/api_docs/kbn_observability_logs_overview.mdx index ab7ecc677c04e..736523bbd1b83 100644 --- a/api_docs/kbn_observability_logs_overview.mdx +++ b/api_docs/kbn_observability_logs_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-logs-overview title: "@kbn/observability-logs-overview" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-logs-overview plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-logs-overview'] --- import kbnObservabilityLogsOverviewObj from './kbn_observability_logs_overview.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 29 | 0 | 27 | 4 | +| 29 | 0 | 27 | 5 | ## Client diff --git a/api_docs/kbn_observability_synthetics_test_data.mdx b/api_docs/kbn_observability_synthetics_test_data.mdx index 400e8fc63d325..af1fe17052224 100644 --- a/api_docs/kbn_observability_synthetics_test_data.mdx +++ b/api_docs/kbn_observability_synthetics_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-synthetics-test-data title: "@kbn/observability-synthetics-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-synthetics-test-data plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-synthetics-test-data'] --- import kbnObservabilitySyntheticsTestDataObj from './kbn_observability_synthetics_test_data.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index 30fc4af847d7c..f1bbdfac697b8 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index bfc30e3b604ea..5626be167782e 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index e135fb25ccca4..84b58776b775f 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-11-27 +date: 2024-12-03 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 1e7f125a18e95..959b2ad430261 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-11-27 +date: 2024-12-03 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 e53eadf3719ef..95aabcc3d4074 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 1fcfd291de8f0..37e99b6c8f23c 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index b7b87a404fe60..01143124a8119 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-11-27 +date: 2024-12-03 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_check.mdx b/api_docs/kbn_plugin_check.mdx index 074594a14e587..a8529cd3e4b91 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 9f85984661599..cd46b3b93b5a3 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-11-27 +date: 2024-12-03 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 93278861bd30e..d209418616b10 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index b6045a6ad1a3c..45859f56729f0 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.devdocs.json b/api_docs/kbn_presentation_publishing.devdocs.json index 96ab95f427e63..46dd41e293a4c 100644 --- a/api_docs/kbn_presentation_publishing.devdocs.json +++ b/api_docs/kbn_presentation_publishing.devdocs.json @@ -8023,6 +8023,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.PublishesWritableDataViews", + "type": "Type", + "tags": [], + "label": "PublishesWritableDataViews", + "description": [], + "signature": [ + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataViews", + "text": "PublishesDataViews" + }, + " & { setDataViews: (dataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]) => void; }" + ], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_data_views.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.PublishesWritablePanelDescription", diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index 81195e61af60b..55e3be661aca6 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 228 | 0 | 192 | 6 | +| 229 | 0 | 193 | 6 | ## Client diff --git a/api_docs/kbn_product_doc_artifact_builder.mdx b/api_docs/kbn_product_doc_artifact_builder.mdx index 7aaf4c37e72fe..1d145c2963921 100644 --- a/api_docs/kbn_product_doc_artifact_builder.mdx +++ b/api_docs/kbn_product_doc_artifact_builder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-artifact-builder title: "@kbn/product-doc-artifact-builder" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-artifact-builder plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-artifact-builder'] --- import kbnProductDocArtifactBuilderObj from './kbn_product_doc_artifact_builder.devdocs.json'; diff --git a/api_docs/kbn_product_doc_common.devdocs.json b/api_docs/kbn_product_doc_common.devdocs.json index 57e3e65f89df3..f5c8ea4e0e653 100644 --- a/api_docs/kbn_product_doc_common.devdocs.json +++ b/api_docs/kbn_product_doc_common.devdocs.json @@ -426,7 +426,7 @@ "label": "productDocIndexPrefix", "description": [], "signature": [ - "\".kibana-ai-product-doc\"" + "\".kibana_ai_product_doc\"" ], "path": "x-pack/packages/ai-infra/product-doc-common/src/indices.ts", "deprecated": false, diff --git a/api_docs/kbn_product_doc_common.mdx b/api_docs/kbn_product_doc_common.mdx index ab656a1f448ae..ff9efa88f98b0 100644 --- a/api_docs/kbn_product_doc_common.mdx +++ b/api_docs/kbn_product_doc_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-common title: "@kbn/product-doc-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-common'] --- import kbnProductDocCommonObj from './kbn_product_doc_common.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index bccca9d1f1b16..32ba388ea4293 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 72d0a299c38d6..c19773b55d58c 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 87cef87a24811..6e6c4e356054b 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index cc9293576f890..3499369aa5cc3 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 2f186e7da7f6f..42b1829b1a1fd 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 4f67992abc20d..b87aca0b8cc8d 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 7e72de2663036..caf56b307d1ce 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 88b08491fe38a..9459e13934e85 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index c33b41bda0af0..a81f9b215954e 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index e924715ea5473..7aedab1a9b11d 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 1fc0d6d99a945..78d6597cdca31 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index f090aeb04676a..9fed1ad6757a8 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 2f3a09f85aa88..b9f838f9b0769 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index ed3f01411a66f..e557cff63b8dd 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 7cab43ee4a465..beb73cf75b9e5 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 947373cc20a3f..f093fe90c5b87 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index 7eb55e92e8696..82e042aef1c85 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 7a537e5395cb2..3f70bdb817dcb 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 2020b3b896ef5..3cc02580d869f 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 5817d80ec0d94..fc4a512b1afaa 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index 9f2403b5d5fb7..ef46224ef48f1 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index 3af6321d7ced0..16a17ea81b44c 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 6816a1d7c0ac7..6ae5fbbc4999b 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index e36f346583367..d2db28bae21bd 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 75ff17b33ad70..58115068d6d1c 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 5477b41583a6e..e4078c796b5cf 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 0054831a5bcfa..b69b31c42766c 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 37124caa8b220..323a53ab8beb8 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_response_ops_rule_params.mdx b/api_docs/kbn_response_ops_rule_params.mdx index 19ff579d00d8f..c3e71da7ac36f 100644 --- a/api_docs/kbn_response_ops_rule_params.mdx +++ b/api_docs/kbn_response_ops_rule_params.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-rule-params title: "@kbn/response-ops-rule-params" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-rule-params plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-rule-params'] --- import kbnResponseOpsRuleParamsObj from './kbn_response_ops_rule_params.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 71adbdc37516c..fe5fd4236fe4b 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index c467c8888c64b..2f7a740e3cbfe 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index d0804315010df..7157417647b2f 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 9167d9794ae00..a916eba9f065c 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 7ba1049ac71d1..7d311e0e8872d 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 4fd15c4e01644..3899d5cc19efc 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index bf3ee8d29afaa..e6c7e1e08ae1e 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_saved_search_component.devdocs.json b/api_docs/kbn_saved_search_component.devdocs.json new file mode 100644 index 0000000000000..faaed21b5130e --- /dev/null +++ b/api_docs/kbn_saved_search_component.devdocs.json @@ -0,0 +1,301 @@ +{ + "id": "@kbn/saved-search-component", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.LazySavedSearchComponent", + "type": "Function", + "tags": [], + "label": "LazySavedSearchComponent", + "description": [], + "signature": [ + "React.ForwardRefExoticComponent<", + { + "pluginId": "@kbn/saved-search-component", + "scope": "public", + "docId": "kibKbnSavedSearchComponentPluginApi", + "section": "def-public.SavedSearchComponentProps", + "text": "SavedSearchComponentProps" + }, + " & React.RefAttributes<{}>>" + ], + "path": "packages/kbn-saved-search-component/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.LazySavedSearchComponent.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/ts5.0/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies", + "type": "Interface", + "tags": [], + "label": "SavedSearchComponentDependencies", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.searchSource", + "type": "Object", + "tags": [], + "label": "searchSource", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ISearchStartSearchSource", + "text": "ISearchStartSearchSource" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.dataViews", + "type": "Object", + "tags": [], + "label": "dataViews", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps", + "type": "Interface", + "tags": [], + "label": "SavedSearchComponentProps", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.dependencies", + "type": "Object", + "tags": [], + "label": "dependencies", + "description": [], + "signature": [ + { + "pluginId": "@kbn/saved-search-component", + "scope": "public", + "docId": "kibKbnSavedSearchComponentPluginApi", + "section": "def-public.SavedSearchComponentDependencies", + "text": "SavedSearchComponentDependencies" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.index", + "type": "string", + "tags": [], + "label": "index", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.query", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.filters", + "type": "Array", + "tags": [], + "label": "filters", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.timestampField", + "type": "string", + "tags": [], + "label": "timestampField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.height", + "type": "CompoundType", + "tags": [], + "label": "height", + "description": [], + "signature": [ + "Property", + ".Height | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.displayOptions", + "type": "Object", + "tags": [], + "label": "displayOptions", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_saved_search_component.mdx b/api_docs/kbn_saved_search_component.mdx new file mode 100644 index 0000000000000..6d72787f6d76a --- /dev/null +++ b/api_docs/kbn_saved_search_component.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: kibKbnSavedSearchComponentPluginApi +slug: /kibana-dev-docs/api/kbn-saved-search-component +title: "@kbn/saved-search-component" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/saved-search-component plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-search-component'] +--- +import kbnSavedSearchComponentObj from './kbn_saved_search_component.devdocs.json'; + + + +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 15 | 0 | 14 | 0 | + +## Client + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_scout.devdocs.json b/api_docs/kbn_scout.devdocs.json index 8766dbc9f9f4d..8d2b4e60a782d 100644 --- a/api_docs/kbn_scout.devdocs.json +++ b/api_docs/kbn_scout.devdocs.json @@ -17,7 +17,1369 @@ "objects": [] }, "common": { - "classes": [], + "classes": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client", + "type": "Class", + "tags": [], + "label": "Client", + "description": [], + "signature": [ + "default", + " extends ", + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.diagnostic", + "type": "Object", + "tags": [], + "label": "diagnostic", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.name", + "type": "CompoundType", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string | symbol" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.connectionPool", + "type": "Object", + "tags": [], + "label": "connectionPool", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.transport", + "type": "Object", + "tags": [], + "label": "transport", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.serializer", + "type": "Object", + "tags": [], + "label": "serializer", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.helpers", + "type": "Object", + "tags": [], + "label": "helpers", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [], + "signature": [ + "ClientOptions" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.child", + "type": "Function", + "tags": [], + "label": "child", + "description": [], + "signature": [ + "(opts: ", + "ClientOptions", + ") => ", + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.child.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [], + "signature": [ + "ClientOptions" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.close", + "type": "Function", + "tags": [], + "label": "close", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient", + "type": "Class", + "tags": [], + "label": "KbnClient", + "description": [], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.status", + "type": "Object", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "KbnClientStatus" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.plugins", + "type": "Object", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "KbnClientPlugins" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.version", + "type": "Object", + "tags": [], + "label": "version", + "description": [], + "signature": [ + "KbnClientVersion" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.savedObjects", + "type": "Object", + "tags": [], + "label": "savedObjects", + "description": [], + "signature": [ + "KbnClientSavedObjects" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.spaces", + "type": "Object", + "tags": [], + "label": "spaces", + "description": [], + "signature": [ + "KbnClientSpaces" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + "KbnClientUiSettings" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.importExport", + "type": "Object", + "tags": [], + "label": "importExport", + "description": [], + "signature": [ + "KbnClientImportExport" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nBasic Kibana server client that implements common behaviors for talking\nto the Kibana server from dev tooling." + ], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.KbnClientOptions", + "text": "KbnClientOptions" + } + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.request", + "type": "Function", + "tags": [], + "label": "request", + "description": [ + "\nMake a direct request to the Kibana server" + ], + "signature": [ + "(options: ", + "ReqOptions", + ") => Promise<", + "AxiosResponse", + ">" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.request.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "ReqOptions" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.resolveUrl", + "type": "Function", + "tags": [], + "label": "resolveUrl", + "description": [], + "signature": [ + "(relativeUrl: string) => string" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.resolveUrl.$1", + "type": "string", + "tags": [], + "label": "relativeUrl", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl", + "type": "Class", + "tags": [], + "label": "KibanaUrl", + "description": [], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.baseUrl", + "type": "Object", + "tags": [], + "label": "#baseUrl", + "description": [], + "signature": [ + "URL" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "baseUrl", + "description": [], + "signature": [ + "URL" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [ + "\nGet an absolute URL based on Kibana's URL" + ], + "signature": [ + "(rel?: string | undefined, options?: ", + "PathOptions", + " | undefined) => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get.$1", + "type": "string", + "tags": [], + "label": "rel", + "description": [ + "relative url, resolved relative to Kibana's url" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "optional modifications to apply to the URL" + ], + "signature": [ + "PathOptions", + " | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app", + "type": "Function", + "tags": [], + "label": "app", + "description": [ + "\nGet the URL for an app" + ], + "signature": [ + "(appName: string, options?: ", + "PathOptions", + " | undefined) => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app.$1", + "type": "string", + "tags": [], + "label": "appName", + "description": [ + "name of the app to get the URL for" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "optional modifications to apply to the URL" + ], + "signature": [ + "PathOptions", + " | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.toString", + "type": "Function", + "tags": [], + "label": "toString", + "description": [], + "signature": [ + "() => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager", + "type": "Class", + "tags": [], + "label": "SamlSessionManager", + "description": [ + "\nManages cookies associated with user roles" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.SamlSessionManagerOptions", + "text": "SamlSessionManagerOptions" + } + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole", + "type": "Function", + "tags": [], + "label": "getApiCredentialsForRole", + "description": [], + "signature": [ + "(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined) => Promise<{ Cookie: string; }>" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope", + "type": "Function", + "tags": [], + "label": "getInteractiveUserSessionCookieWithRoleScope", + "description": [], + "signature": [ + "(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined) => Promise" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getEmail", + "type": "Function", + "tags": [], + "label": "getEmail", + "description": [], + "signature": [ + "(role: string) => Promise" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getEmail.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getUserData", + "type": "Function", + "tags": [], + "label": "getUserData", + "description": [], + "signature": [ + "(role: string) => Promise<", + "UserProfile", + ">" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getUserData.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog", + "type": "Class", + "tags": [], + "label": "ToolingLog", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + }, + " implements ", + { + "pluginId": "@kbn/some-dev-log", + "scope": "common", + "docId": "kibKbnSomeDevLogPluginApi", + "section": "def-common.SomeDevLog", + "text": "SomeDevLog" + } + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "writerConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLogTextWriterConfig", + "text": "ToolingLogTextWriterConfig" + }, + " | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLogOptions", + "text": "ToolingLogOptions" + }, + " | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getIndent", + "type": "Function", + "tags": [], + "label": "getIndent", + "description": [ + "\nGet the current indentation level of the ToolingLog" + ], + "signature": [ + "() => number" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent", + "type": "Function", + "tags": [], + "label": "indent", + "description": [], + "signature": [ + "{ (delta: number): void; (delta: number, block: () => Promise): Promise; (delta: number, block: () => T): T; }" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent.$1", + "type": "number", + "tags": [], + "label": "delta", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent.$2", + "type": "Function", + "tags": [], + "label": "block", + "description": [], + "signature": [ + "(() => T | Promise) | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.verbose", + "type": "Function", + "tags": [], + "label": "verbose", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.verbose.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.debug", + "type": "Function", + "tags": [], + "label": "debug", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.debug.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.info", + "type": "Function", + "tags": [], + "label": "info", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.info.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.success", + "type": "Function", + "tags": [], + "label": "success", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.success.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.warning", + "type": "Function", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.warning.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.error", + "type": "Function", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "(error: string | Error) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.error.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "string | Error" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.write", + "type": "Function", + "tags": [], + "label": "write", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.write.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getWriters", + "type": "Function", + "tags": [], + "label": "getWriters", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.setWriters", + "type": "Function", + "tags": [], + "label": "setWriters", + "description": [], + "signature": [ + "(writers: ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.setWriters.$1", + "type": "Array", + "tags": [], + "label": "writers", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getWritten$", + "type": "Function", + "tags": [], + "label": "getWritten$", + "description": [], + "signature": [ + "() => ", + "Observable", + "<", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Message", + "text": "Message" + }, + ">" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.withType", + "type": "Function", + "tags": [], + "label": "withType", + "description": [ + "\nCreate a new ToolingLog which sets a different \"type\", allowing messages to be filtered out by \"source\"" + ], + "signature": [ + "(type: string) => ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.withType.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "A string that will be passed along with messages from this logger which can be used to filter messages with `ignoreSources`" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], "functions": [ { "parentPluginId": "@kbn/scout", @@ -289,7 +1651,13 @@ "text": "ScoutPage" }, "; kbnUrl: ", - "KibanaUrl", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.KibanaUrl", + "text": "KibanaUrl" + }, "; } & ", { "pluginId": "@kbn/scout", @@ -319,6 +1687,84 @@ } ], "interfaces": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture", + "type": "Interface", + "tags": [], + "label": "EsArchiverFixture", + "description": [], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded", + "type": "Function", + "tags": [], + "label": "loadIfNeeded", + "description": [], + "signature": [ + "(name: string, performance?: ", + { + "pluginId": "@kbn/es-archiver", + "scope": "common", + "docId": "kibKbnEsArchiverPluginApi", + "section": "def-common.LoadActionPerfOptions", + "text": "LoadActionPerfOptions" + }, + " | undefined) => Promise>" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded.$2", + "type": "Object", + "tags": [], + "label": "performance", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-archiver", + "scope": "common", + "docId": "kibKbnEsArchiverPluginApi", + "section": "def-common.LoadActionPerfOptions", + "text": "LoadActionPerfOptions" + }, + " | undefined" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/scout", "id": "def-common.PageObjects", @@ -357,6 +1803,34 @@ "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.dashboard", + "type": "Object", + "tags": [], + "label": "dashboard", + "description": [], + "signature": [ + "DashboardApp" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.filterBar", + "type": "Object", + "tags": [], + "label": "filterBar", + "description": [], + "signature": [ + "FilterBar" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -448,13 +1922,17 @@ "Page", " & { gotoApp: (appName: string, options?: { referer?: string | undefined; timeout?: number | undefined; waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\" | \"commit\" | undefined; } | undefined) => Promise<", "Response", - " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", + " | null>; waitForLoadingIndicatorHidden: () => Promise<", + "ElementHandle", + " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isVisible: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", "Locator", " | undefined; hasNot?: ", "Locator", " | undefined; hasNotText?: string | RegExp | undefined; hasText?: string | RegExp | undefined; } | undefined) => ", "Locator", - "; }; }" + "; waitForSelector: (selector: string, options?: PageWaitForSelectorOptions | undefined) => Promise<", + "ElementHandle", + " | null>; typeWithDelay: (selector: string, text: string, options?: { delay: number; } | undefined) => Promise; clearInput: (selector: string) => Promise; }; }" ], "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", "deprecated": false, @@ -583,7 +2061,13 @@ "label": "kbnUrl", "description": [], "signature": [ - "KibanaUrl" + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.KibanaUrl", + "text": "KibanaUrl" + } ], "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", "deprecated": false, @@ -623,6 +2107,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + "UiSettingsFixture" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/scout", "id": "def-common.ScoutWorkerFixtures.esArchiver", @@ -631,7 +2129,13 @@ "label": "esArchiver", "description": [], "signature": [ - "EsArchiverFixture" + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.EsArchiverFixture", + "text": "EsArchiverFixture" + } ], "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", "deprecated": false, @@ -669,18 +2173,24 @@ "type": "Type", "tags": [], "label": "ScoutPage", - "description": [], + "description": [ + "\nExtends the Playwright 'Page' interface with methods specific to Kibana.\nReasons to use 'ReturnType' instead of Explicit Typings:\n- DRY Principle: automatically stays in sync with the Playwright API, reducing maintenance overhead.\n- Future-Proofing: If Playwright changes the return type of methods, these types will update accordingly.\nRecommendation: define Explicit Types as return types only if methods (e.g. 'typeWithDelay')\nhave any additional logic or Kibana-specific behavior." + ], "signature": [ "Page", " & { gotoApp: (appName: string, options?: { referer?: string | undefined; timeout?: number | undefined; waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\" | \"commit\" | undefined; } | undefined) => Promise<", "Response", - " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", + " | null>; waitForLoadingIndicatorHidden: () => Promise<", + "ElementHandle", + " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isVisible: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", "Locator", " | undefined; hasNot?: ", "Locator", " | undefined; hasNotText?: string | RegExp | undefined; hasText?: string | RegExp | undefined; } | undefined) => ", "Locator", - "; }; }" + "; waitForSelector: (selector: string, options?: PageWaitForSelectorOptions | undefined) => Promise<", + "ElementHandle", + " | null>; typeWithDelay: (selector: string, text: string, options?: { delay: number; } | undefined) => Promise; clearInput: (selector: string) => Promise; }; }" ], "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", "deprecated": false, diff --git a/api_docs/kbn_scout.mdx b/api_docs/kbn_scout.mdx index fc0a4a55f5cb0..b868c759fe850 100644 --- a/api_docs/kbn_scout.mdx +++ b/api_docs/kbn_scout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-scout title: "@kbn/scout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/scout plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/scout'] --- import kbnScoutObj from './kbn_scout.devdocs.json'; @@ -21,13 +21,16 @@ Contact [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) for | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 34 | 0 | 26 | 5 | +| 119 | 0 | 86 | 8 | ## Common ### Functions +### Classes + + ### Interfaces diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index 6b7c2863fb6b4..be432e83d6061 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_components.devdocs.json b/api_docs/kbn_search_api_keys_components.devdocs.json index f27bd9c7b38e5..1f515d4600918 100644 --- a/api_docs/kbn_search_api_keys_components.devdocs.json +++ b/api_docs/kbn_search_api_keys_components.devdocs.json @@ -110,9 +110,9 @@ "label": "useSearchApiKey", "description": [], "signature": [ - "() => { displayedApiKey: string | null; apiKey: string | null; toggleApiKeyVisibility: () => void; updateApiKey: ({ id, encoded }: { id: string; encoded: string; }) => void; status: ", + "() => { apiKey: string | null; toggleApiKeyVisibility: () => void; updateApiKey: ({ id, encoded }: { id: string; encoded: string; }) => void; status: ", "Status", - "; apiKeyIsVisible: boolean; }" + "; }" ], "path": "packages/kbn-search-api-keys-components/src/hooks/use_search_api_key.ts", "deprecated": false, diff --git a/api_docs/kbn_search_api_keys_components.mdx b/api_docs/kbn_search_api_keys_components.mdx index 9e32961b64fd2..4f4ef836fc8d5 100644 --- a/api_docs/kbn_search_api_keys_components.mdx +++ b/api_docs/kbn_search_api_keys_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-components title: "@kbn/search-api-keys-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-components'] --- import kbnSearchApiKeysComponentsObj from './kbn_search_api_keys_components.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_server.mdx b/api_docs/kbn_search_api_keys_server.mdx index f964a26913018..d065d49232bdc 100644 --- a/api_docs/kbn_search_api_keys_server.mdx +++ b/api_docs/kbn_search_api_keys_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-server title: "@kbn/search-api-keys-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-server'] --- import kbnSearchApiKeysServerObj from './kbn_search_api_keys_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index f7eae2906d5fa..0cf7b6a852222 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.devdocs.json b/api_docs/kbn_search_connectors.devdocs.json index a4721ab941fbd..31b9ff22f7e0d 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -1338,6 +1338,98 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName", + "type": "Function", + "tags": [], + "label": "generateConnectorName", + "description": [], + "signature": [ + "(client: ", + { + "pluginId": "@kbn/core-elasticsearch-server", + "scope": "server", + "docId": "kibKbnCoreElasticsearchServerPluginApi", + "section": "def-server.ElasticsearchClient", + "text": "ElasticsearchClient" + }, + ", connectorType: string, isNative: boolean, userConnectorName?: string | undefined) => Promise<{ connectorName: string; indexName: string; }>" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$1", + "type": "Object", + "tags": [], + "label": "client", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-elasticsearch-server", + "scope": "server", + "docId": "kibKbnCoreElasticsearchServerPluginApi", + "section": "def-server.ElasticsearchClient", + "text": "ElasticsearchClient" + } + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$2", + "type": "string", + "tags": [], + "label": "connectorType", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$3", + "type": "boolean", + "tags": [], + "label": "isNative", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$4", + "type": "string", + "tags": [], + "label": "userConnectorName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.getConnectorsDict", @@ -7161,6 +7253,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.MANAGED_CONNECTOR_INDEX_PREFIX", + "type": "string", + "tags": [], + "label": "MANAGED_CONNECTOR_INDEX_PREFIX", + "description": [], + "signature": [ + "\"content-\"" + ], + "path": "packages/kbn-search-connectors/constants/connectors.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [ diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 5f506dd4921ef..5ba6722443d61 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3948 | 0 | 3948 | 0 | +| 3954 | 0 | 3954 | 0 | ## Common diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index 9caa2d60c31c7..ed60763f601ef 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index 2063ec1c691de..f5d8aa98d839e 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 5adcbb8ccbaee..2171084dde531 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_shared_ui.mdx b/api_docs/kbn_search_shared_ui.mdx index 88b4e273aeb19..ebad34cd2bd63 100644 --- a/api_docs/kbn_search_shared_ui.mdx +++ b/api_docs/kbn_search_shared_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-shared-ui title: "@kbn/search-shared-ui" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-shared-ui plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-shared-ui'] --- import kbnSearchSharedUiObj from './kbn_search_shared_ui.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index 54f909b775e75..4ead6d8c9968a 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index b0faee7b97c73..3b3612d40743d 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index d0fb9a96eaea9..c9ed463683ca7 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core_common.mdx b/api_docs/kbn_security_authorization_core_common.mdx index 1bb94c6cf57c8..74f2c37abcd95 100644 --- a/api_docs/kbn_security_authorization_core_common.mdx +++ b/api_docs/kbn_security_authorization_core_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core-common title: "@kbn/security-authorization-core-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core-common'] --- import kbnSecurityAuthorizationCoreCommonObj from './kbn_security_authorization_core_common.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.devdocs.json b/api_docs/kbn_security_form_components.devdocs.json index 4fb983c29b46c..9dccf63965ba1 100644 --- a/api_docs/kbn_security_form_components.devdocs.json +++ b/api_docs/kbn_security_form_components.devdocs.json @@ -246,11 +246,11 @@ "DisambiguateSet", " & { labelType?: \"legend\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", "DisambiguateSet", " & { labelType?: \"label\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", { "pluginId": "@kbn/security-form-components", "scope": "common", @@ -276,11 +276,11 @@ "DisambiguateSet", " & { labelType?: \"legend\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", "DisambiguateSet", " & { labelType?: \"label\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", { "pluginId": "@kbn/security-form-components", "scope": "common", diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 47437d592722d..b7cf6dbe337d9 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 1931aaeaf2acc..59150e002d372 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index bcb07d4d2c8b9..7860df573efe2 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index b674626c7ab5d..a80602c8ca044 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index a9f246fea7042..dacb26ea39d3c 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index 502f13fc78721..0227136a820fe 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.devdocs.json b/api_docs/kbn_security_solution_distribution_bar.devdocs.json index edcd3cad12f9b..51fdf64ef88c7 100644 --- a/api_docs/kbn_security_solution_distribution_bar.devdocs.json +++ b/api_docs/kbn_security_solution_distribution_bar.devdocs.json @@ -84,7 +84,7 @@ "distribution data points" ], "signature": [ - "{ key: string; count: number; color: string; label?: React.ReactNode; }[]" + "{ key: string; count: number; color: string; label?: React.ReactNode; isCurrentFilter?: boolean | undefined; filter?: (() => void) | undefined; reset?: ((event: React.MouseEvent) => void) | undefined; }[]" ], "path": "x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx", "deprecated": false, diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 22c0c39665d35..6db68ac78df81 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 8aa713181a3c9..cfae5b98640c1 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 8f53c46843f82..a6c6a0bc8b4cc 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index cf94be7c1c79f..b59dc38d0d65f 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index a5fa006f232d3..51a54e68c6d39 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_security_ui_components.mdx b/api_docs/kbn_security_ui_components.mdx index c6120ea841a86..995a86bd52251 100644 --- a/api_docs/kbn_security_ui_components.mdx +++ b/api_docs/kbn_security_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-ui-components title: "@kbn/security-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-ui-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-ui-components'] --- import kbnSecurityUiComponentsObj from './kbn_security_ui_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 1b8b600fec88a..375acf6485700 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index f41c419da349a..c8fbe41adc821 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 0437ead62ccf1..29c7acff0d35b 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 984b91729c33e..7c918c80d9e82 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 9cb7c1d0db50a..ea26ddab6a94d 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-11-27 +date: 2024-12-03 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 bdbbb949838ce..3c9d620a2b6fd 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 59cfed50b0648..1cadbad642b59 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-11-27 +date: 2024-12-03 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 5cbecf20ea963..c97c65e926681 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-11-27 +date: 2024-12-03 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 82984ed41ffda..475670953a925 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-11-27 +date: 2024-12-03 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 eb87e141bce59..35eabcf16f602 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 d0ff5b5323c42..5acbde47bdf9a 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-11-27 +date: 2024-12-03 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 4db584dec3150..65cd4a1e4db0d 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-11-27 +date: 2024-12-03 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 1010b2e479c1e..47034d9238fd1 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-11-27 +date: 2024-12-03 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 534cb7a844102..f3596fe402d03 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 82a7a70913612..796441a88f2fb 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-11-27 +date: 2024-12-03 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 4b76722fe919f..b69ebb507b467 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-11-27 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_securitysolution_utils.devdocs.json index d799309b1821d..8fa42be623b61 100644 --- a/api_docs/kbn_securitysolution_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_utils.devdocs.json @@ -466,13 +466,13 @@ "label": "isAggregatingQuery", "description": [], "signature": [ - "(ast: ", + "(astExpression: ", { "pluginId": "@kbn/esql-ast", "scope": "common", "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLAst", - "text": "ESQLAst" + "section": "def-common.ESQLAstQueryExpression", + "text": "ESQLAstQueryExpression" }, ") => boolean" ], @@ -483,17 +483,17 @@ { "parentPluginId": "@kbn/securitysolution-utils", "id": "def-common.isAggregatingQuery.$1", - "type": "Array", + "type": "Object", "tags": [], - "label": "ast", + "label": "astExpression", "description": [], "signature": [ { "pluginId": "@kbn/esql-ast", "scope": "common", "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLAst", - "text": "ESQLAst" + "section": "def-common.ESQLAstQueryExpression", + "text": "ESQLAstQueryExpression" } ], "path": "packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts", diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 2c0b783e8a087..3bd451984fd2e 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-11-27 +date: 2024-12-03 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 5039e84813a6c..e321b98542f9f 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-11-27 +date: 2024-12-03 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 f2cea68949da8..c7f27f9b9f5b5 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index 0fbc897614a6f..38a373079d662 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index 5f7fe9cd0452e..e439098ba3498 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 7355312b07b1a..7f064985631c8 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 79f296696df85..d22ce4172aa69 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index ba7cc81977ee7..5963967d8bcf7 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 056ca23fa031f..f8a1e6cc37fdc 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 6c60190f560a5..3442c34bdbb85 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index e685f98085168..a174fe461afa2 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index d56f711b3634b..75eddfcf4e298 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 9065489a458c8..07f0127523f52 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 299b2ab8f6c5f..a4aa5096b5024 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index d4026db8ba55c..28ae6716f3ee9 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-11-27 +date: 2024-12-03 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 9f53727103c4f..e0021c7cc2165 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-11-27 +date: 2024-12-03 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 fedc348e0e19d..9ec03f02229b8 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 2c3ee97011b40..76154e77fe208 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 158b9bfaa2bf7..a17e903b64496 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index f6c5296df07a9..d9b5c7ee64b38 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index ca367c1c75b53..7dd85fe4f2e9b 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 469ff0d279c8f..fe89aed708712 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 94c614c59444b..6db103816744f 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 7b602a4f8c856..db98855c73e14 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 10c2212658bcc..5aaa50af518fd 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index e4d6e11a0029a..900dd0cc61236 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 784f285881882..c165fada0a6b8 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index f4870f02cef4a..fb041bb4b4dff 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 92d3efe8e0bb9..64c89f8895884 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 f4a5f3185f228..45b634682af66 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-11-27 +date: 2024-12-03 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 30bfcbe6badca..99b41b41931c3 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 a36e675757b70..c5b24bded152a 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-11-27 +date: 2024-12-03 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 252962cb13146..2c2fc5d749455 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 32b4ca7713135..1de155e2e8a79 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-11-27 +date: 2024-12-03 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 4c3c1d5586b24..1283451195537 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 ddc7dad8bca2e..8827e97e3052b 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-11-27 +date: 2024-12-03 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 70d0e91053545..69a3478aed4b7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 a82b61374ec01..be2cff9d73bd0 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-11-27 +date: 2024-12-03 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 1ea2a0e628719..81784c4767202 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-11-27 +date: 2024-12-03 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 a3d6b2436eef9..a57150fe66db4 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 9937862f5989a..079c87c939d2c 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 f64ea62e2e2fd..6d4583ce83a9b 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-11-27 +date: 2024-12-03 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 5bce08b27de16..18b7993305585 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-11-27 +date: 2024-12-03 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 06b71413ef883..97f657a264c89 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 568e8d452f6bd..7e4a649020b6d 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index c30cd738ea6c7..e0fad918bab42 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-11-27 +date: 2024-12-03 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 972ebd591be7f..c90d09d43a625 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-11-27 +date: 2024-12-03 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 4616c74660cd4..820ab7568a2fb 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-11-27 +date: 2024-12-03 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 7b66b7990b0b9..f19e0a6f0d20b 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-11-27 +date: 2024-12-03 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_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 1d5ef962201d2..96f5752bb324e 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index 02306a305a8ac..0263713730b97 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index e394facd20948..2a99930e98c06 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.devdocs.json b/api_docs/kbn_slo_schema.devdocs.json index 13f17bcf471b8..57d2f788dc036 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -606,7 +606,7 @@ "label": "CreateSLOInput", "description": [], "signature": [ - "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" + "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/create.ts", "deprecated": false, @@ -661,7 +661,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" + " | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/create.ts", "deprecated": false, @@ -835,7 +835,7 @@ "label": "FindSLODefinitionsResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: { id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }[]; }" + "{ page: number; perPage: number; total: number; results: { id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_definition.ts", "deprecated": false, @@ -895,7 +895,7 @@ "label": "FindSLOResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" + "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find.ts", "deprecated": false, @@ -993,7 +993,7 @@ "label": "GetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get.ts", "deprecated": false, @@ -1263,7 +1263,7 @@ "label": "ResetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/reset.ts", "deprecated": false, @@ -1278,7 +1278,7 @@ "label": "SLODefinitionResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1293,7 +1293,7 @@ "label": "SLOWithSummaryResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1398,7 +1398,7 @@ "label": "UpdateSLOInput", "description": [], "signature": [ - "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | undefined; timeWindow?: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" + "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | undefined; timeWindow?: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -1453,7 +1453,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" + " | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -1468,7 +1468,7 @@ "label": "UpdateSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -3250,7 +3250,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; tags: ", + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>; tags: ", "ArrayC", "<", "StringC", @@ -5171,6 +5177,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -5194,7 +5202,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -6811,6 +6827,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -6834,7 +6852,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -9945,6 +9971,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -9968,7 +9996,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -12867,7 +12903,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>" + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/slo.ts", "deprecated": false, @@ -14444,6 +14486,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -14467,7 +14511,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -14554,6 +14606,8 @@ "label": "settingsSchema", "description": [], "signature": [ + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -14577,7 +14631,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>" + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/slo.ts", "deprecated": false, @@ -15982,6 +16044,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -16005,7 +16069,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -17562,6 +17634,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -17585,7 +17659,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -20241,7 +20323,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; tags: ", + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>; tags: ", "ArrayC", "<", "StringC", @@ -21664,6 +21752,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -21687,7 +21777,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 49208babb9f35..acb6a8173eebd 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 94315ab07ab97..1c0edd62e378a 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-11-27 +date: 2024-12-03 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_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index d3573c4de6c9b..92284a5b23c21 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_sse_utils.mdx b/api_docs/kbn_sse_utils.mdx index c0c0f197a9099..59a5694310014 100644 --- a/api_docs/kbn_sse_utils.mdx +++ b/api_docs/kbn_sse_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils title: "@kbn/sse-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils'] --- import kbnSseUtilsObj from './kbn_sse_utils.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_client.mdx b/api_docs/kbn_sse_utils_client.mdx index 865b21e5ed770..938c72543d30f 100644 --- a/api_docs/kbn_sse_utils_client.mdx +++ b/api_docs/kbn_sse_utils_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-client title: "@kbn/sse-utils-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-client plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-client'] --- import kbnSseUtilsClientObj from './kbn_sse_utils_client.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_server.mdx b/api_docs/kbn_sse_utils_server.mdx index 1220c14d865ea..b644dd00225be 100644 --- a/api_docs/kbn_sse_utils_server.mdx +++ b/api_docs/kbn_sse_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-server title: "@kbn/sse-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-server plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-server'] --- import kbnSseUtilsServerObj from './kbn_sse_utils_server.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 8bbaf36c12506..381a352aa0af6 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-11-27 +date: 2024-12-03 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 dc7dca636a577..a6775c662e9ba 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-11-27 +date: 2024-12-03 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 6644534d432c9..1fc5797c7af79 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index af4234d42c686..711deb91b9bbe 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index 260ba4f93fcb1..af24792bd8bfd 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index a10fea3342914..334f1857e3fa4 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-11-27 +date: 2024-12-03 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 fe621891c107c..7d2f6d15b2500 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 965dc09c56ab8..f7625b6d00353 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index d9b4a0e8c7f4a..fb69f623ea84d 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-11-27 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_test_subj_selector.devdocs.json index 2ab9cc3c4a7a3..dafcf5ceb970e 100644 --- a/api_docs/kbn_test_subj_selector.devdocs.json +++ b/api_docs/kbn_test_subj_selector.devdocs.json @@ -26,7 +26,7 @@ "tags": [], "label": "subj", "description": [ - "\nConverts a testSubject selector into a CSS selector.\n\ntestSubject selector syntax rules:\n\n - `data-test-subj` values can include spaces\n\n - prefixing a value with `*` will allow matching a `data-test-subj` attribute containing at least one occurrence of value within the string.\n - example: `*foo`\n - css equivalent: `[data-test-subj*=\"foo\"]`\n - DOM match example:
data-test-subj=\"bar-foo\"
\n\n - prefixing a value with `~` will allow matching a `data-test-subj` attribute represented as a whitespace-separated list of words, one of which is exactly value\n - example: `~foo`\n - css equivalent: `[data-test-subj~=\"foo\"]`\n - DOM match example:
data-test-subj=\"foo bar\"
\n\n - the `>` character is used between two values to indicate that the value on the right must match an element inside an element matched by the value on the left\n - example: `foo > bar`\n - css equivalent: `[data-test-subj=foo] [data-test-subj=bar]`\n - DOM match example:\n
data-test-subj=\"foo\"\n
data-test-subj=\"bar\"
\n
\n\n - the `&` character is used between two values to indicate that the value on both sides must both match the element\n - example: `foo & bar`\n - css equivalent: `[data-test-subj=foo][data-test-subj=bar]`\n - DOM match example:
data-test-subj=\"foo bar\"
" + "\nConverts a testSubject selector into a CSS selector.\n\ntestSubject selector syntax rules:\n\n - `data-test-subj` values can include spaces\n\n - prefixing a value with `*` will allow matching a `data-test-subj` attribute containing at least one occurrence of value within the string.\n - example: `*foo`\n - css equivalent: `[data-test-subj*=\"foo\"]`\n - DOM match example:
\n\n - prefixing a value with `^` will allow matching a `data-test-subj` attribute beginning with the specified value.\n - example: `^foo`\n - css equivalent: `[data-test-subj^=\"foo\"]`\n - DOM match example:
\n\n - prefixing a value with `~` will allow matching a `data-test-subj` attribute represented as a whitespace-separated list of words, one of which is exactly value\n - example: `~foo`\n - css equivalent: `[data-test-subj~=\"foo\"]`\n - DOM match example:
\n\n - the `>` character is used between two values to indicate that the value on the right must match an element inside an element matched by the value on the left\n - example: `foo > bar`\n - css equivalent: `[data-test-subj=foo] [data-test-subj=bar]`\n - DOM match example:\n
\n
\n
\n\n - the `&` character is used between two values to indicate that the value on both sides must both match the element\n - example: `foo & bar`\n - css equivalent: `[data-test-subj=foo][data-test-subj=bar]`\n - DOM match example:
" ], "signature": [ "(selector: string) => string" diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 20131af8fdd11..02c286b503a3c 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index 931533e753d55..acc61504485a3 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 75c65b965c12d..edf7f58b4bdac 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_transpose_utils.mdx b/api_docs/kbn_transpose_utils.mdx index 0786faeb3f72d..6c930f1bafb85 100644 --- a/api_docs/kbn_transpose_utils.mdx +++ b/api_docs/kbn_transpose_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-transpose-utils title: "@kbn/transpose-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/transpose-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/transpose-utils'] --- import kbnTransposeUtilsObj from './kbn_transpose_utils.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 07fb33ec689d7..f7d11a0f01fc7 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index e974b03d384f9..0783a6380f402 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index e9faf5dc2b8ba..e0587ede01cf2 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index ff75129261113..4c60563b2291f 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index c5630a61cd392..dad32cac09d53 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 503a30242f6e2..a340b03cf1a98 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 8f9cbe27fcaf9..9dabec875b0bb 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.devdocs.json b/api_docs/kbn_unified_data_table.devdocs.json index 1398b8b7116ac..0a59133908c68 100644 --- a/api_docs/kbn_unified_data_table.devdocs.json +++ b/api_docs/kbn_unified_data_table.devdocs.json @@ -823,7 +823,7 @@ "label": "UnifiedDataTable", "description": [], "signature": [ - "({ ariaLabelledBy, columns, columnsMeta, showColumnTokens, canDragAndDropColumns, configHeaderRowHeight, headerRowHeightState, onUpdateHeaderRowHeight, controlColumnIds, rowAdditionalLeadingControls, dataView, loadingState, onFilter, onResize, onSetColumns, onSort, rows, searchDescription, searchTitle, settings, showTimeCol, showFullScreenButton, sort, useNewFieldsApi, isSortEnabled, isPaginationEnabled, cellActionsTriggerId, cellActionsMetadata, cellActionsHandling, visibleCellActions, className, rowHeightState, onUpdateRowHeight, maxAllowedSampleSize, sampleSizeState, onUpdateSampleSize, isPlainRecord, rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, services, renderCustomGridBody, renderCustomToolbar, externalControlColumns, trailingControlColumns, totalHits, onFetchMoreRecords, renderDocumentView, setExpandedDoc, expandedDoc, configRowHeight, showMultiFields, maxDocFieldsDisplayed, externalAdditionalControls, rowsPerPageOptions, externalCustomRenderers, additionalFieldGroups, consumer, componentsTourSteps, gridStyleOverride, rowLineHeightOverride, customGridColumnsConfiguration, enableComparisonMode, cellContext, renderCellPopover, getRowIndicator, dataGridDensityState, onUpdateDataGridDensity, }: ", + "({ ariaLabelledBy, columns, columnsMeta, showColumnTokens, canDragAndDropColumns, configHeaderRowHeight, headerRowHeightState, onUpdateHeaderRowHeight, controlColumnIds, rowAdditionalLeadingControls, dataView, loadingState, onFilter, onResize, onSetColumns, onSort, rows, searchDescription, searchTitle, settings, showTimeCol, showFullScreenButton, sort, useNewFieldsApi, isSortEnabled, isPaginationEnabled, cellActionsTriggerId, cellActionsMetadata, cellActionsHandling, visibleCellActions, className, rowHeightState, onUpdateRowHeight, maxAllowedSampleSize, sampleSizeState, onUpdateSampleSize, isPlainRecord, rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, services, renderCustomGridBody, renderCustomToolbar, externalControlColumns, trailingControlColumns, totalHits, onFetchMoreRecords, renderDocumentView, setExpandedDoc, expandedDoc, configRowHeight, showMultiFields, maxDocFieldsDisplayed, externalAdditionalControls, rowsPerPageOptions, externalCustomRenderers, additionalFieldGroups, consumer, componentsTourSteps, gridStyleOverride, rowLineHeightOverride, customGridColumnsConfiguration, enableComparisonMode, cellContext, renderCellPopover, getRowIndicator, dataGridDensityState, onUpdateDataGridDensity, onUpdatePageIndex, }: ", { "pluginId": "@kbn/unified-data-table", "scope": "public", @@ -842,7 +842,7 @@ "id": "def-public.UnifiedDataTable.$1", "type": "Object", "tags": [], - "label": "{\n ariaLabelledBy,\n columns,\n columnsMeta,\n showColumnTokens,\n canDragAndDropColumns,\n configHeaderRowHeight,\n headerRowHeightState,\n onUpdateHeaderRowHeight,\n controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,\n rowAdditionalLeadingControls,\n dataView,\n loadingState,\n onFilter,\n onResize,\n onSetColumns,\n onSort,\n rows,\n searchDescription,\n searchTitle,\n settings,\n showTimeCol,\n showFullScreenButton = true,\n sort,\n useNewFieldsApi,\n isSortEnabled = true,\n isPaginationEnabled = true,\n cellActionsTriggerId,\n cellActionsMetadata,\n cellActionsHandling = 'replace',\n visibleCellActions,\n className,\n rowHeightState,\n onUpdateRowHeight,\n maxAllowedSampleSize,\n sampleSizeState,\n onUpdateSampleSize,\n isPlainRecord = false,\n rowsPerPageState,\n onUpdateRowsPerPage,\n onFieldEdited,\n services,\n renderCustomGridBody,\n renderCustomToolbar,\n externalControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n trailingControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n totalHits,\n onFetchMoreRecords,\n renderDocumentView,\n setExpandedDoc,\n expandedDoc,\n configRowHeight,\n showMultiFields = true,\n maxDocFieldsDisplayed = 50,\n externalAdditionalControls,\n rowsPerPageOptions,\n externalCustomRenderers,\n additionalFieldGroups,\n consumer = 'discover',\n componentsTourSteps,\n gridStyleOverride,\n rowLineHeightOverride,\n customGridColumnsConfiguration,\n enableComparisonMode,\n cellContext,\n renderCellPopover,\n getRowIndicator,\n dataGridDensityState,\n onUpdateDataGridDensity,\n}", + "label": "{\n ariaLabelledBy,\n columns,\n columnsMeta,\n showColumnTokens,\n canDragAndDropColumns,\n configHeaderRowHeight,\n headerRowHeightState,\n onUpdateHeaderRowHeight,\n controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,\n rowAdditionalLeadingControls,\n dataView,\n loadingState,\n onFilter,\n onResize,\n onSetColumns,\n onSort,\n rows,\n searchDescription,\n searchTitle,\n settings,\n showTimeCol,\n showFullScreenButton = true,\n sort,\n useNewFieldsApi,\n isSortEnabled = true,\n isPaginationEnabled = true,\n cellActionsTriggerId,\n cellActionsMetadata,\n cellActionsHandling = 'replace',\n visibleCellActions,\n className,\n rowHeightState,\n onUpdateRowHeight,\n maxAllowedSampleSize,\n sampleSizeState,\n onUpdateSampleSize,\n isPlainRecord = false,\n rowsPerPageState,\n onUpdateRowsPerPage,\n onFieldEdited,\n services,\n renderCustomGridBody,\n renderCustomToolbar,\n externalControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n trailingControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n totalHits,\n onFetchMoreRecords,\n renderDocumentView,\n setExpandedDoc,\n expandedDoc,\n configRowHeight,\n showMultiFields = true,\n maxDocFieldsDisplayed = 50,\n externalAdditionalControls,\n rowsPerPageOptions,\n externalCustomRenderers,\n additionalFieldGroups,\n consumer = 'discover',\n componentsTourSteps,\n gridStyleOverride,\n rowLineHeightOverride,\n customGridColumnsConfiguration,\n enableComparisonMode,\n cellContext,\n renderCellPopover,\n getRowIndicator,\n dataGridDensityState,\n onUpdateDataGridDensity,\n onUpdatePageIndex,\n}", "description": [], "signature": [ { @@ -1962,6 +1962,40 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-public.UnifiedDataTableProps.onUpdatePageIndex", + "type": "Function", + "tags": [], + "label": "onUpdatePageIndex", + "description": [ + "\n\nthis callback is triggered when user navigates to a different page\n" + ], + "signature": [ + "((pageIndex: number) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-public.UnifiedDataTableProps.onUpdatePageIndex.$1", + "type": "number", + "tags": [], + "label": "pageIndex", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/unified-data-table", "id": "def-public.UnifiedDataTableProps.maxAllowedSampleSize", @@ -3144,7 +3178,7 @@ "label": "CustomCellRenderer", "description": [], "signature": [ - "{ [x: string]: (props: ", + "{ [x: string]: React.FunctionComponent<", { "pluginId": "@kbn/unified-data-table", "scope": "public", @@ -3152,7 +3186,7 @@ "section": "def-public.DataGridCellValueElementProps", "text": "DataGridCellValueElementProps" }, - ") => React.ReactElement>; }" + ">; }" ], "path": "packages/kbn-unified-data-table/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 9ba3044c787cf..b8313c9fd1fd6 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 184 | 0 | 108 | 1 | +| 186 | 0 | 109 | 1 | ## Client diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 0c42dee27645c..a0b82df40b47f 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 80155d8d967f7..c1f54be675e47 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index d234172e216c7..1db7abc927de5 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index a1556d9d72c6e..56383bcf3c70b 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index c1f579039184e..5222c704661ab 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index b519f806f5f11..cd218a070b837 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-11-27 +date: 2024-12-03 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 51fea8124e488..87ecf211ccc4c 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-11-27 +date: 2024-12-03 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 90730ab48a86a..4b49518487ea0 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-11-27 +date: 2024-12-03 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 eb9196017c44e..3dec60b9418d8 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 1c0655410c276..c68e7f789a972 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 5614966b6c2b7..c2fcf6978f621 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index c3466c23666ee..231e5ddd1e1a5 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 66b96500615a7..0517fbdcc6409 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod.mdx b/api_docs/kbn_zod.mdx index 5ea77fdff0450..086e598844ac2 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 842215662e874..963af679b9ae0 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index a5f9500bcc4d9..5aa289d152798 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-11-27 +date: 2024-12-03 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 d66db2328964d..5d988082e379e 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-11-27 +date: 2024-12-03 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 234b3d3057c89..6787003f78943 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-11-27 +date: 2024-12-03 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 d856cd01edeb1..5c57711ffd9d7 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-11-27 +date: 2024-12-03 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 a4880de1f3b94..013522ad1bafa 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -361,15 +361,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -377,6 +369,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", @@ -567,7 +567,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -689,7 +689,15 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined>; dataViews: ", + " | undefined>; rendered$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; dataViews: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -895,7 +903,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -1127,7 +1135,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -6860,7 +6868,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { "pluginId": "@kbn/core-saved-objects-common", "scope": "common", @@ -7374,7 +7382,7 @@ }, " | undefined; textBased?: ", "TextBasedPersistedState", - " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { "pluginId": "uiActions", "scope": "public", @@ -7659,7 +7667,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { "pluginId": "@kbn/core-saved-objects-common", "scope": "common", @@ -8173,7 +8181,7 @@ }, " | undefined; textBased?: ", "TextBasedPersistedState", - " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { "pluginId": "uiActions", "scope": "public", @@ -8531,15 +8539,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -8547,6 +8547,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", @@ -8783,15 +8791,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -8799,6 +8799,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", @@ -16060,7 +16068,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { "pluginId": "@kbn/core-saved-objects-common", "scope": "common", @@ -16574,7 +16582,7 @@ }, " | undefined; textBased?: ", "TextBasedPersistedState", - " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { "pluginId": "uiActions", "scope": "public", @@ -16844,7 +16852,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { "pluginId": "@kbn/core-saved-objects-common", "scope": "common", @@ -17358,7 +17366,7 @@ }, " | undefined; textBased?: ", "TextBasedPersistedState", - " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { "pluginId": "uiActions", "scope": "public", @@ -17977,15 +17985,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -17993,6 +17993,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", @@ -18183,7 +18191,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -18305,7 +18313,15 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined>; dataViews: ", + " | undefined>; rendered$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; dataViews: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -18511,7 +18527,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -18743,7 +18759,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -20523,15 +20539,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -20539,6 +20547,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", @@ -20729,7 +20745,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -20851,7 +20867,15 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined>; dataViews: ", + " | undefined>; rendered$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; dataViews: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -21057,7 +21081,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -21289,7 +21313,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -21794,7 +21818,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { "pluginId": "@kbn/core-saved-objects-common", "scope": "common", @@ -22308,7 +22332,7 @@ }, " | undefined; textBased?: ", "TextBasedPersistedState", - " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { "pluginId": "uiActions", "scope": "public", @@ -22587,7 +22611,7 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, - " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -22931,15 +22955,7 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; executionContext?: ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined; style?: React.CSSProperties | undefined; className?: string | undefined; noPadding?: boolean | undefined; viewMode?: ", + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -22947,6 +22963,14 @@ "section": "def-public.ViewMode", "text": "ViewMode" }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, " | undefined; enhancements?: { dynamicActions: ", { "pluginId": "uiActionsEnhanced", diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 1053c1a363cb4..2a0fa0fac8df9 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-11-27 +date: 2024-12-03 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 7139470821d9a..50c415af42cc7 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-11-27 +date: 2024-12-03 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 aef305a9652ac..4bb9d046ea56c 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.devdocs.json b/api_docs/licensing.devdocs.json index fc5da83ec0228..954110ba3ede9 100644 --- a/api_docs/licensing.devdocs.json +++ b/api_docs/licensing.devdocs.json @@ -850,14 +850,6 @@ "plugin": "watcher", "path": "x-pack/plugins/watcher/public/plugin.ts" }, - { - "plugin": "profiling", - "path": "x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx" - }, { "plugin": "slo", "path": "x-pack/plugins/observability_solution/slo/public/plugin.ts" diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 0dc44f35fd50d..8e4aa9179672c 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 3ea036b45b10d..3666a3ae56f0b 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 5c1119bc2417a..03c4dff3ed058 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/llm_tasks.mdx b/api_docs/llm_tasks.mdx index 6b9175b51a876..d8ce2477322ab 100644 --- a/api_docs/llm_tasks.mdx +++ b/api_docs/llm_tasks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/llmTasks title: "llmTasks" image: https://source.unsplash.com/400x175/?github description: API docs for the llmTasks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'llmTasks'] --- import llmTasksObj from './llm_tasks.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index ab782dca89d96..583d6c438c7a4 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/logs_explorer.devdocs.json b/api_docs/logs_explorer.devdocs.json index fefcffd0f9174..d05a47b7590d0 100644 --- a/api_docs/logs_explorer.devdocs.json +++ b/api_docs/logs_explorer.devdocs.json @@ -311,7 +311,13 @@ "description": [], "signature": [ "Pick>, \"data\" | \"history\" | \"uiSettings\" | \"timefilter\" | \"filterManager\"> & { urlStateStorage: ", { "pluginId": "kibanaUtils", diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index aec2ef03542b2..baefde7680169 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.devdocs.json b/api_docs/logs_shared.devdocs.json index 70accf5e5f656..9f8ec3fc78fad 100644 --- a/api_docs/logs_shared.devdocs.json +++ b/api_docs/logs_shared.devdocs.json @@ -3164,6 +3164,46 @@ "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "logsShared", + "id": "def-public.LogsSharedClientStartDeps.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "logsShared", + "id": "def-public.LogsSharedClientStartDeps.savedSearch", + "type": "Object", + "tags": [], + "label": "savedSearch", + "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearchPublicPluginStart", + "text": "SavedSearchPublicPluginStart" + } + ], + "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 03fcb888b90e1..86875b5059324 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 314 | 0 | 285 | 34 | +| 316 | 0 | 287 | 34 | ## Client diff --git a/api_docs/management.mdx b/api_docs/management.mdx index c2154bed565c5..2a0acf38e95f9 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-11-27 +date: 2024-12-03 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 07826aec2031f..7b7896bf2a386 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 12b0559d25c0f..fa7e566583a8f 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index bef04739c6024..7d48db8921317 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; Exposes utilities for accessing metrics data -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 92e79b3890919..7f436ec133229 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 5fd183f536f1c..db1d4898b1296 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index ba80c072ea6e0..23ecf827b250f 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-11-27 +date: 2024-12-03 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 c1dfb7d2309f6..e761debc4aa24 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-11-27 +date: 2024-12-03 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 4ea357e1202fb..699697eb251b3 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-11-27 +date: 2024-12-03 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 bbfc2171f1053..245a48893309c 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 4c755d12088b9..cabc113dcef80 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 8b5cd24055795..6fffbb0d80b3e 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 48c5cad2a518a..89b649746b7af 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -1008,7 +1008,7 @@ "label": "useAnnotations", "description": [], "signature": [ - "({ domain, editAnnotation, slo, setEditAnnotation, }?: { slo?: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined; editAnnotation?: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null | undefined; setEditAnnotation?: ((annotation: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null) => void) | undefined; domain?: { min: string | number; max: string | number; } | undefined; }) => { annotations: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; })[]; onAnnotationClick: (annotations: { rects: ", + "({ domain, editAnnotation, slo, setEditAnnotation, }?: { slo?: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined; editAnnotation?: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null | undefined; setEditAnnotation?: ((annotation: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null) => void) | undefined; domain?: { min: string | number; max: string | number; } | undefined; }) => { annotations: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; })[]; onAnnotationClick: (annotations: { rects: ", "RectAnnotationEvent", "[]; lines: ", "LineAnnotationEvent", @@ -1045,7 +1045,7 @@ "label": "slo", "description": [], "signature": [ - "({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined" + "({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined" ], "path": "x-pack/plugins/observability_solution/observability/public/components/annotations/use_annotations.tsx", "deprecated": false, @@ -8640,7 +8640,7 @@ "label": "tags", "description": [], "signature": [ - "string[]" + "string[] | undefined" ], "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", "deprecated": false, diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 857eff114d15d..e41db59251190 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index a11aa4c4548bd..322e88d27cdf3 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -2418,18 +2418,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -3398,18 +3388,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -5115,18 +5095,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -6322,18 +6292,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -7301,7 +7261,17 @@ "section": "def-common.AssistantScope", "text": "AssistantScope" }, - "[]; }; }" + "[]; }; } | { type: ", + { + "pluginId": "observabilityAIAssistant", + "scope": "public", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-public.ObservabilityAIAssistantTelemetryEventType", + "text": "ObservabilityAIAssistantTelemetryEventType" + }, + ".InsightResponse; payload: ", + "InsightResponse", + "; }" ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts", "deprecated": false, @@ -8062,18 +8032,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 7aea15538434d..70d5cc9a5c0be 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 296 | 1 | 294 | 27 | +| 296 | 1 | 294 | 28 | ## Client diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 25cc572e48811..41bb15ce4fe02 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 123ebf99cfa0d..39d707158fee5 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index f0d959907a4fc..9a8534c58aea4 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 5498c34441e51..0446c0eb1c386 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 650647b25e4e4..3784f6203d55b 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 527d4f217c463..bf64f7fd4fd91 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 9fa5aa16a85b9..3916ebb5cb959 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index c98e40129d81f..d321ce8d8ca21 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,25 +15,25 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 893 | 761 | 43 | +| 895 | 762 | 43 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 54580 | 240 | 40995 | 2024 | +| 54810 | 240 | 41195 | 2033 | ## Plugin Directory | Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 322 | 0 | 316 | 37 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 321 | 0 | 315 | 37 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 4 | 0 | 4 | 1 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 4 | 0 | 4 | 1 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 72 | 0 | 8 | 2 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 880 | 1 | 848 | 50 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 119 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 3 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 93 | 0 | 93 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 60 | 1 | 59 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | @@ -65,9 +65,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 4 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin introduces the concept of data set quality, where users can easily get an overview on the data sets they have. | 14 | 0 | 14 | 8 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 15 | 0 | 9 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 148 | 0 | 100 | 24 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 214 | 0 | 166 | 30 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 35 | 0 | 33 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 16 | 0 | 15 | 3 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 26 | 0 | 23 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | Server APIs for the Elastic AI Assistant | 53 | 0 | 38 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 578 | 1 | 468 | 9 | @@ -75,7 +75,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 54 | 0 | 47 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | | | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 2 | 0 | 2 | 0 | -| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 35 | 0 | 35 | 2 | +| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 37 | 0 | 37 | 3 | | entityManagerApp | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 0 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 99 | 3 | 97 | 3 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 25 | 0 | 9 | 0 | @@ -104,7 +104,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | 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. | 89 | 0 | 89 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 3 | 0 | 3 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1432 | 5 | 1306 | 82 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1435 | 5 | 1309 | 82 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -116,7 +116,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 244 | 0 | 239 | 1 | -| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 40 | 0 | 29 | 6 | +| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 40 | 0 | 28 | 6 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 24 | 0 | 24 | 5 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | @@ -138,14 +138,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | A dashboard panel for creating links to dashboards or external links. | 5 | 0 | 5 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 227 | 0 | 98 | 52 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 5 | 0 | 1 | 2 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 15 | 0 | 13 | 7 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 15 | 0 | 13 | 7 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin provides a LogsExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption. | 120 | 4 | 120 | 23 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes the shared components and APIs to access and visualize logs. | 314 | 0 | 285 | 34 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes the shared components and APIs to access and visualize logs. | 316 | 0 | 287 | 34 | | logstash | [@elastic/logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 44 | 0 | 44 | 7 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 213 | 0 | 207 | 28 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 60 | 0 | 60 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 135 | 6 | 135 | 5 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | Exposes utilities for accessing metrics data | 135 | 6 | 135 | 5 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 148 | 3 | 63 | 104 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 2 | 0 | 2 | 0 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 15 | 3 | 13 | 1 | @@ -155,7 +155,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 697 | 2 | 689 | 23 | -| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 296 | 1 | 294 | 27 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 296 | 1 | 294 | 28 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 4 | 0 | 4 | 0 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 19 | 0 | 19 | 1 | @@ -174,7 +174,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 263 | 0 | 226 | 10 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 24 | 0 | 19 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 97 | 2 | 96 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 25 | 0 | 25 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 26 | 0 | 26 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 148 | 0 | 139 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 0 | 30 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 105 | 0 | 58 | 0 | @@ -191,7 +191,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 22 | 0 | 16 | 1 | | searchprofiler | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 455 | 0 | 238 | 0 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 187 | 0 | 119 | 33 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 191 | 0 | 123 | 34 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | ESS customizations for Security Solution. | 6 | 0 | 6 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 7 | 0 | 7 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 25 | 0 | 24 | 0 | @@ -199,7 +199,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Serverless customizations for search. | 7 | 0 | 7 | 0 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 134 | 0 | 134 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds URL Service and sharing capabilities to Kibana | 136 | 0 | 73 | 15 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 45 | 0 | 45 | 4 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 47 | 0 | 47 | 2 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 22 | 1 | 22 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 269 | 0 | 73 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 25 | 0 | 25 | 3 | @@ -220,7 +220,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 156 | 0 | 110 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 212 | 0 | 145 | 11 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 15 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 70 | 0 | 35 | 6 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 69 | 0 | 35 | 6 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 149 | 2 | 112 | 21 | | upgradeAssistant | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | This plugin visualizes data from Heartbeat, and integrates with other Observability solutions. | 1 | 0 | 1 | 0 | @@ -251,7 +251,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 14 | 0 | 14 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 64 | 0 | 64 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3 | 0 | 3 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 37 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 66 | 0 | 0 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 27 | 3 | 27 | 0 | @@ -260,7 +260,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 243 | 0 | 240 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 33 | 0 | 33 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 31 | 0 | 15 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 320 | 0 | 304 | 8 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 321 | 0 | 305 | 8 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 73 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | @@ -283,8 +283,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 62 | 0 | 17 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 89 | 1 | 89 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 109 | 0 | 107 | 1 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 93 | 1 | 93 | 0 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 122 | 0 | 120 | 1 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 20 | 0 | 15 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 41 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | @@ -513,28 +513,28 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 38 | 2 | 33 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 37 | 0 | 34 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 284 | 0 | 234 | 4 | -| | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 79 | 0 | 79 | 2 | +| | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 80 | 0 | 80 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 5 | 0 | 5 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 57 | 0 | 30 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 28 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 16 | 0 | 8 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 42 | 0 | 41 | 0 | -| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 169 | 0 | 140 | 10 | +| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 170 | 0 | 141 | 10 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 442 | 0 | 405 | 0 | -| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 50 | 0 | 50 | 0 | +| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 51 | 0 | 51 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 55 | 0 | 40 | 7 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 32 | 0 | 19 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 271 | 1 | 210 | 14 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 30 | 0 | 30 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 277 | 1 | 216 | 36 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 283 | 1 | 222 | 36 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 29 | 0 | 12 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 83 | 0 | 74 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 205 | 0 | 193 | 12 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 44 | 0 | 17 | 3 | +| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 41 | 0 | 14 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 22 | 0 | 18 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 51 | 0 | 42 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | @@ -544,7 +544,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 26 | 0 | 26 | 1 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 16 | 0 | 16 | 1 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 17 | 0 | 17 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 17 | 0 | 12 | 11 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 47 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 33 | 3 | 24 | 6 | @@ -630,7 +630,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 5 | 0 | 5 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 99 | 1 | 99 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 6 | 0 | 6 | 1 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 29 | 0 | 27 | 4 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 29 | 0 | 27 | 5 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 4 | 0 | 4 | 1 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 12 | 0 | 12 | 0 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 15 | 0 | 15 | 0 | @@ -643,7 +643,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 92 | 0 | 80 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 228 | 0 | 192 | 6 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 229 | 0 | 193 | 6 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 31 | 0 | 31 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 168 | 0 | 55 | 0 | @@ -682,12 +682,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 16 | 0 | 16 | 1 | | | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 138 | 0 | 135 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | -| | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 34 | 0 | 26 | 5 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 15 | 0 | 14 | 0 | +| | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 119 | 0 | 86 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 35 | 0 | 34 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 8 | 0 | 8 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3 | 0 | 3 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 76 | 0 | 76 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3948 | 0 | 3948 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3954 | 0 | 3954 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 1 | 17 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 36 | 0 | 34 | 3 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 18 | 1 | @@ -802,7 +803,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 42 | 0 | 28 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 61 | 0 | 52 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 0 | 8 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 184 | 0 | 108 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 186 | 0 | 109 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 0 | 17 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 317 | 0 | 288 | 8 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 30e56a507fd3d..ba7ad19e35c1a 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index c87e0a9aefca3..608ee8ec6052a 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/product_doc_base.mdx b/api_docs/product_doc_base.mdx index 1fe521075cede..b4d5a3abd7bbd 100644 --- a/api_docs/product_doc_base.mdx +++ b/api_docs/product_doc_base.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/productDocBase title: "productDocBase" image: https://source.unsplash.com/400x175/?github description: API docs for the productDocBase plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'productDocBase'] --- import productDocBaseObj from './product_doc_base.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index dca76f8388da3..e483cfd96c659 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 566f2b3d126bb..acc71b8508e7f 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 9ca25457dae61..0c8f1c61f827d 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-11-27 +date: 2024-12-03 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 316dfcf95eaea..35957e03e59f3 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-11-27 +date: 2024-12-03 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 42dd1516b2ee8..774258153466e 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-11-27 +date: 2024-12-03 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 27a10bb09d724..a2312f45d5df3 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-11-27 +date: 2024-12-03 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 8321e60c933f9..4e8cb4f0a32f2 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-11-27 +date: 2024-12-03 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 f7a3f5b821d77..bb90830dba62f 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.devdocs.json b/api_docs/saved_objects_finder.devdocs.json index 866969ae30c37..c6104240fef8c 100644 --- a/api_docs/saved_objects_finder.devdocs.json +++ b/api_docs/saved_objects_finder.devdocs.json @@ -533,6 +533,20 @@ "path": "src/plugins/saved_objects_finder/common/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "savedObjectsFinder", + "id": "def-common.FinderAttributes.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects_finder/common/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index cb0a09e213dea..0d9cdee95f93a 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 25 | 0 | 25 | 1 | +| 26 | 0 | 26 | 1 | ## Client diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 129833149c054..15bd21d5b6d18 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-11-27 +date: 2024-12-03 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 21edf7a60459d..ec1638958e02a 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-11-27 +date: 2024-12-03 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 44be8d2c7cdb8..a613566c60776 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-11-27 +date: 2024-12-03 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 32db8d3748397..56a59050b9058 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-11-27 +date: 2024-12-03 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 fa44815df37bf..0086b8cb10a91 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-11-27 +date: 2024-12-03 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 138fc0763518a..c06d70c38dd90 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_assistant.mdx b/api_docs/search_assistant.mdx index 3c767ab7c4f17..30858fc27f43b 100644 --- a/api_docs/search_assistant.mdx +++ b/api_docs/search_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchAssistant title: "searchAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the searchAssistant plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 536490b5a4397..72f4f46714b77 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index 0ebde9ca89756..c90944ba62182 100644 --- a/api_docs/search_homepage.mdx +++ b/api_docs/search_homepage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchHomepage title: "searchHomepage" image: https://source.unsplash.com/400x175/?github description: API docs for the searchHomepage plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx index 862a504c74bc1..fd27a066f0051 100644 --- a/api_docs/search_indices.mdx +++ b/api_docs/search_indices.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchIndices title: "searchIndices" image: https://source.unsplash.com/400x175/?github description: API docs for the searchIndices plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchIndices'] --- import searchIndicesObj from './search_indices.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index 91bb5db0b40f2..56b3db801e11a 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_navigation.mdx b/api_docs/search_navigation.mdx index b3734a97c31be..13ec3c71cb616 100644 --- a/api_docs/search_navigation.mdx +++ b/api_docs/search_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNavigation title: "searchNavigation" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNavigation plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNavigation'] --- import searchNavigationObj from './search_navigation.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index bc0a416ae3018..87e79557b6d02 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 71dfbbf04e9d0..25725925c071e 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 77e436392a4ac..202af84020403 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-11-27 +date: 2024-12-03 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 f76d77c7255ef..8320b9f633933 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -266,6 +266,108 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures", + "type": "Function", + "tags": [], + "label": "registerDiscoverSharedFeatures", + "description": [], + "signature": [ + "(core: ", + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreSetup", + "text": "CoreSetup" + }, + "<", + "StartPluginsDependencies", + ", ", + { + "pluginId": "securitySolution", + "scope": "public", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + }, + ">, plugins: ", + "SetupPlugins", + ") => Promise" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreSetup", + "text": "CoreSetup" + }, + "<", + "StartPluginsDependencies", + ", ", + { + "pluginId": "securitySolution", + "scope": "public", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + }, + ">" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures.$2", + "type": "Object", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "SetupPlugins" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.getLazyDiscoverSharedDeps", + "type": "Function", + "tags": [], + "label": "getLazyDiscoverSharedDeps", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false @@ -1829,7 +1931,7 @@ "label": "setComponents", "description": [], "signature": [ - "(components: Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean | undefined; }>; DashboardsLandingCallout: React.ComponentType<{}>; }>) => void" + "(components: Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean | undefined; }>; DashboardsLandingCallout: React.ComponentType<{}>; EnablementModalCallout: React.ComponentType<{}>; }>) => void" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -1844,7 +1946,7 @@ "label": "components", "description": [], "signature": [ - "{ GetStarted?: React.ComponentType<{ indicesExist?: boolean | undefined; }> | undefined; DashboardsLandingCallout?: React.ComponentType<{}> | undefined; }" + "{ GetStarted?: React.ComponentType<{ indicesExist?: boolean | undefined; }> | undefined; DashboardsLandingCallout?: React.ComponentType<{}> | undefined; EnablementModalCallout?: React.ComponentType<{}> | undefined; }" ], "path": "x-pack/plugins/security_solution/public/contract_components.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 4083a669c38c8..1568e2234ad23 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 187 | 0 | 119 | 33 | +| 191 | 0 | 123 | 34 | ## Client diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index e6e8818af2bd2..37360609c9b10 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index f957d34c50f49..21ecd0fdc8eec 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 63d306f2f3d08..6d3ac863fa09d 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 19f6de85128ce..868a24e2392bb 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index 609a70a6e03ab..9ff4dc7b3e9e1 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index eaf55aaa1f37b..4065f8ed52a9c 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-11-27 +date: 2024-12-03 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 c2f84cff0da3c..922d5c624d3a0 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.devdocs.json b/api_docs/slo.devdocs.json index 6252ccc31c977..9c7a930086fa6 100644 --- a/api_docs/slo.devdocs.json +++ b/api_docs/slo.devdocs.json @@ -384,6 +384,27 @@ "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "slo", + "id": "def-public.SLOPublicPluginsSetup.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityPluginSetup", + "text": "SecurityPluginSetup" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/slo/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1076,6 +1097,27 @@ "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "slo", + "id": "def-public.SLOPublicPluginsStart.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityPluginStart", + "text": "SecurityPluginStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/slo/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1100,9 +1142,7 @@ "section": "def-common.RecursivePartial", "text": "RecursivePartial" }, - "<", - "CreateSLOForm", - "<{ type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }>> | undefined; }>; }" + "<{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }> | undefined; }>; }" ], "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, @@ -1137,8 +1177,8 @@ "text": "LocatorPublic" }, "<", - "SloEditLocatorParams", - ">; sloListLocator: ", + "RecursivePartial", + "<{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }>>; sloListLocator: ", { "pluginId": "share", "scope": "common", diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 7221d862703b4..dd266c0213c99 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 45 | 0 | 45 | 4 | +| 47 | 0 | 47 | 2 | ## Client diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index a60deea776cc2..a7b3818f4a82d 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-11-27 +date: 2024-12-03 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 698996a783b9a..635c21d795899 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-11-27 +date: 2024-12-03 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 23b76b482ca62..c787e7566524d 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-11-27 +date: 2024-12-03 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 b6d5cb7ea7fc6..abd4c2df3a8da 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/streams.devdocs.json b/api_docs/streams.devdocs.json index 1d744b0580b2f..bf552dc47d88d 100644 --- a/api_docs/streams.devdocs.json +++ b/api_docs/streams.devdocs.json @@ -107,9 +107,9 @@ "StreamsRouteHandlerResources", ", { definitions: { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }[]; trees: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]; trees: ", "StreamTree", "[]; }, undefined>; \"DELETE /api/streams/{id}\": ", { @@ -175,9 +175,9 @@ "StreamsRouteHandlerResources", ", { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -201,29 +201,29 @@ "Condition", "; }, { id: string; condition?: ", "Condition", - "; }>, \"many\">>; }, { id: Zod.ZodString; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>, \"many\">>; }, { id: Zod.ZodString; managed: Zod.ZodDefault; unmanaged_elasticsearch_assets: Zod.ZodOptional; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }>, \"many\">>; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }>; condition: Zod.ZodType<", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }>; condition: Zod.ZodType<", "Condition", ", Zod.ZodTypeDef, ", "Condition", - ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", "; }; }>, ", "StreamsRouteHandlerResources", @@ -311,9 +311,9 @@ "signature": [ "{ id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }[]" + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]" ], "path": "x-pack/plugins/streams/server/lib/streams/stream_crud.ts", "deprecated": false, @@ -392,9 +392,9 @@ "StreamsRouteHandlerResources", ", { definitions: { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }[]; trees: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]; trees: ", "StreamTree", "[]; }, undefined>; \"DELETE /api/streams/{id}\": ", { @@ -460,9 +460,9 @@ "StreamsRouteHandlerResources", ", { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -486,29 +486,29 @@ "Condition", "; }, { id: string; condition?: ", "Condition", - "; }>, \"many\">>; }, { id: Zod.ZodString; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>, \"many\">>; }, { id: Zod.ZodString; managed: Zod.ZodDefault; unmanaged_elasticsearch_assets: Zod.ZodOptional; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }>, \"many\">>; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }>; condition: Zod.ZodType<", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }>; condition: Zod.ZodType<", "Condition", ", Zod.ZodTypeDef, ", "Condition", - ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", "; }; }>, ", "StreamsRouteHandlerResources", @@ -586,9 +586,9 @@ "signature": [ "{ id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }" + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }" ], "path": "x-pack/plugins/streams/common/types.ts", "deprecated": false, diff --git a/api_docs/streams.mdx b/api_docs/streams.mdx index 4ab302c607777..9c4865f7f286f 100644 --- a/api_docs/streams.mdx +++ b/api_docs/streams.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/streams title: "streams" image: https://source.unsplash.com/400x175/?github description: API docs for the streams plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'streams'] --- import streamsObj from './streams.devdocs.json'; diff --git a/api_docs/streams_app.devdocs.json b/api_docs/streams_app.devdocs.json index 2bb7bd48fb0cb..12a4d9b1b7d5a 100644 --- a/api_docs/streams_app.devdocs.json +++ b/api_docs/streams_app.devdocs.json @@ -114,9 +114,9 @@ "signature": [ "EntityBase & { type: \"stream\"; properties: { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; }" + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; }" ], "path": "x-pack/plugins/streams_app/common/index.ts", "deprecated": false, @@ -133,9 +133,9 @@ "signature": [ "EntityBase & { type: \"stream\"; properties: { id: string; children: { id: string; condition?: ", "Condition", - "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; }" + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; }" ], "path": "x-pack/plugins/streams_app/common/index.ts", "deprecated": false, diff --git a/api_docs/streams_app.mdx b/api_docs/streams_app.mdx index fdca8c54bd473..629a0ca065115 100644 --- a/api_docs/streams_app.mdx +++ b/api_docs/streams_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/streamsApp title: "streamsApp" image: https://source.unsplash.com/400x175/?github description: API docs for the streamsApp plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'streamsApp'] --- import streamsAppObj from './streams_app.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index d94cd09dc2d4a..3a338e11eac2a 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-11-27 +date: 2024-12-03 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 e01e0ffa4de20..ed12ad96ade80 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-11-27 +date: 2024-12-03 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 1ab28d2b1d086..ade6bf4aa32f0 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 36a8703cd22bd..cb5728a3d59f2 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-11-27 +date: 2024-12-03 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 81e97af5bbbe2..3a2034cece75a 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-11-27 +date: 2024-12-03 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 183a364cfeb39..8b41d13110bf2 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-11-27 +date: 2024-12-03 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 6453d27d72ebe..fe7f7d34d99c8 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-11-27 +date: 2024-12-03 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 d9cb680c24d46..9585065993bd3 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-11-27 +date: 2024-12-03 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 05a9af3001dd8..923384e4c2600 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 910d763f585af..76c339e7a7e3a 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 1ca1de3cf2541..3327549edae03 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.devdocs.json b/api_docs/unified_histogram.devdocs.json index c661b482aeedb..0e201c9411bb5 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -549,7 +549,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; isChartLoading?: boolean | undefined; onVisContextChanged?: ((nextVisContext: ", + " | undefined; isChartLoading?: boolean | undefined; breakdownField?: string | undefined; onBreakdownFieldChange?: ((breakdownField: string | undefined) => void) | undefined; onVisContextChanged?: ((nextVisContext: ", { "pluginId": "unifiedHistogram", "scope": "public", @@ -1071,22 +1071,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "unifiedHistogram", - "id": "def-public.UnifiedHistogramState.breakdownField", - "type": "string", - "tags": [], - "label": "breakdownField", - "description": [ - "\nThe current field used for the breakdown" - ], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/unified_histogram/public/container/services/state_service.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "unifiedHistogram", "id": "def-public.UnifiedHistogramState.currentSuggestionContext", @@ -1990,7 +1974,7 @@ "signature": [ "{ refetch: () => void; } & Pick<", "UnifiedHistogramStateService", - ", \"state$\" | \"setChartHidden\" | \"setTopPanelHeight\" | \"setBreakdownField\" | \"setTimeInterval\" | \"setTotalHits\">" + ", \"state$\" | \"setChartHidden\" | \"setTopPanelHeight\" | \"setTimeInterval\" | \"setTotalHits\">" ], "path": "src/plugins/unified_histogram/public/container/container.tsx", "deprecated": false, @@ -2031,7 +2015,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; isChartLoading?: boolean | undefined; onVisContextChanged?: ((nextVisContext: ", + " | undefined; isChartLoading?: boolean | undefined; breakdownField?: string | undefined; onBreakdownFieldChange?: ((breakdownField: string | undefined) => void) | undefined; onVisContextChanged?: ((nextVisContext: ", { "pluginId": "unifiedHistogram", "scope": "public", diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 36654626fa3c3..cb762669e1fe6 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 70 | 0 | 35 | 6 | +| 69 | 0 | 35 | 6 | ## Client diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 8837361d778ea..4a7b6b6a93256 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-11-27 +date: 2024-12-03 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 cb418a94c0d1f..e390173873794 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 5ec7c7d6b98cf..67b588c31ea63 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index a0dcebbecd608..9918c9f120844 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-11-27 +date: 2024-12-03 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 eed811634d732..f9b10099d1e72 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-11-27 +date: 2024-12-03 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 13d305da7ac1a..40dfc1020e700 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-11-27 +date: 2024-12-03 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 268301ad41592..1c52c77a9c374 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-11-27 +date: 2024-12-03 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 c95fbf75c40da..e6d4660542074 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-11-27 +date: 2024-12-03 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 1c74f6cc2f834..d582a5d36f3b7 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-11-27 +date: 2024-12-03 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 4c697f312fe32..58bf93a187797 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-11-27 +date: 2024-12-03 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 a0c0c9f785166..868a64d7ea529 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-11-27 +date: 2024-12-03 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 374642da2531a..46f5b63e4c4ca 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-11-27 +date: 2024-12-03 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 260b7e10d6387..0b7d0f0020d77 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-11-27 +date: 2024-12-03 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 6de5391e65525..edbc75b2fa1a3 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-11-27 +date: 2024-12-03 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 1052b91cba033..f0e417c66112d 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-11-27 +date: 2024-12-03 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 ee06ed70a6989..61634c53a811a 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-11-27 +date: 2024-12-03 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 26842c773bde4..234558c6457ac 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -7050,7 +7050,7 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined; getFilters: () => ", + " | undefined; canLinkToLibrary: (() => Promise) | undefined; canUnlinkFromLibrary: (() => Promise) | undefined; onEdit: () => Promise; isEditingEnabled: () => boolean; getEditHref: () => Promise; getTypeDisplayName: () => string; getFilters: () => ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -7058,7 +7058,7 @@ "section": "def-common.Filter", "text": "Filter" }, - "[]; canLinkToLibrary: (() => Promise) | undefined; canUnlinkFromLibrary: (() => Promise) | undefined; setTimeRange: (timeRange: ", + "[]; setTimeRange: (timeRange: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -7074,7 +7074,7 @@ "section": "def-public.VisualizeInput", "text": "VisualizeInput" }, - "; getDescription: () => string; onEdit: () => Promise; phase$: ", + "; getDescription: () => string; phase$: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -7090,7 +7090,7 @@ "section": "def-public.PhaseEvent", "text": "PhaseEvent" }, - " | undefined>; setPanelTitle: (newTitle: string | undefined) => void; isEditingEnabled: () => boolean; setHidePanelTitle: (hide: boolean | undefined) => void; getTypeDisplayName: () => string; setPanelDescription: (newTitle: string | undefined) => void; render: (domNode: HTMLElement) => Promise; getEditHref: () => Promise; supportedTriggers: () => string[]; getInspectorAdapters: () => ", + " | undefined>; setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; setPanelDescription: (newTitle: string | undefined) => void; render: (domNode: HTMLElement) => Promise; supportedTriggers: () => string[]; getInspectorAdapters: () => ", { "pluginId": "inspector", "scope": "common", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 0716480869c54..ac0e737f773a2 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-11-27 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.es.yml b/config/serverless.es.yml index 4b0d416bacdfc..3132125bfecde 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -59,6 +59,13 @@ xpack.features.overrides: stackAlerts: name: "Alerts" category: "enterpriseSearch" + ### Observability AI Assistant feature is moved to Search and renamed + observabilityAIAssistant: + name: "AI Assistant" + category: "enterpriseSearch" + ### AI Assistant enables the Inventory feature, moving to Search + inventory: + category: "enterpriseSearch" ## Cloud settings xpack.cloud.serverless.project_type: search @@ -127,7 +134,6 @@ xpack.observabilityAIAssistant.enabled: true xpack.searchAssistant.enabled: true xpack.searchAssistant.ui.enabled: true xpack.observabilityAIAssistant.scope: "search" -xpack.observabilityAIAssistant.enableKnowledgeBase: false aiAssistantManagementSelection.preferredAIAssistantType: "observability" xpack.observabilityAiAssistantManagement.logSourcesEnabled: false xpack.observabilityAiAssistantManagement.spacesEnabled: false diff --git a/dev_docs/tutorials/saved_objects.mdx b/dev_docs/tutorials/saved_objects.mdx index 233795374f2e9..71b99e2ae5e7e 100644 --- a/dev_docs/tutorials/saved_objects.mdx +++ b/dev_docs/tutorials/saved_objects.mdx @@ -126,6 +126,56 @@ Do not use field mappings like you would use data types for the columns of a SQL SQL index. Only specify field mappings for the fields you wish to search on or query. By specifying `dynamic: false` in any level of your mappings, Elasticsearch will accept and store any other fields even if they are not specified in your mappings. +Never use `enabled: false` or `index: false` in your mappings. Elasticsearch does not support toggling these mapping options, so if +your plugin ever needs to query the data, you will not be able to do so. Since these fields cannot be queried, they would require +migrating to a new field and making associated code changes. Instead, use `dynamic: false` which provides the same flexibility while +maintaining the future ability to query fields if necessary. + +Here's an example of what NOT to do: + +```ts +export const dashboardVisualization: SavedObjectsType = { + name: 'dashboard_visualization', + ... + mappings: { + properties: { + metadata: { + enabled: false, // ❌ Don't do this + properties: { + created_by: { type: 'keyword' } + } + }, + description: { + index: false, // ❌ Don't do this + type: 'text' + } + } + } +}; +``` + +Instead, use `dynamic: false` if you want to persist data which does not need to be queryable. +```ts +export const dashboardVisualization: SavedObjectsType = { + name: 'dashboard_visualization', + ... + mappings: { + properties: { + dynamic: false, // ✅ Do this instead + metadata: { + // dynamic: false gets inherited from above + properties: { + // `created_by` can now be stored but won't be queryable + } + }, + // `description` can now be stored but won't be queryable + } + } +}; +``` + +This approach maintains flexibility while ensuring all fields remain queryable if needed in the future. + Since Elasticsearch has a default limit of 1000 fields per index, plugins should carefully consider the fields they add to the mappings. Similarly, Saved Object types should never use `dynamic: true` as this can cause an arbitrary amount of fields to be added to the .kibana index. diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 848042e475fee..ef8d4182144f0 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -27,6 +27,59 @@ For information about the {kib} 9.0.0 release, review the following information. [[breaking-changes-9.0.0]] === Breaking changes +[discrete] +.Removed legacy alerting endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `POST /api/alerts/alert/{id?}` has been replaced by `POST /api/alerting/rule/{id?}` +* `GET /api/alerts/alert/{id}` has been replaced by `GET /api/alerting/rule/{id}` +* `PUT /api/alerts/alert/{id}` has been replaced by `PUT /api/alerting/rule/rule/{id}` +* `DELETE: /api/alerts/alert/{id}` has been replaced by `DELETE /api/alerting/rule/{id}` +* `POST /api/alerts/alert/{id}/_disable` has been replaced by `POST /api/alerting/rule/{id}/_disable` +* `POST /api/alerts/alert/{id}/_enable` has been replaced by `POST /api/alerting/rule/{id}/_enable` +* `GET /api/alerts/_find` has been replaced by `GET /api/alerting/rules/_find` +* `GET /api/alerts/_health` has been replaced by `GET /api/alerting/rule/_health` +* `GET /api/alerts/list_alert_types` has been replaced by `GET /api/alerting/rule_types` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_unmute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute` +* `POST /api/alerts/alert/{id}/_mute_all` has been replaced by `POST /api/alerting/rule/{id}/_mute_all` +* `POST /api/alerts/alert/{id}/_unmute_all` has been replaced by `POST /api/alerting/rule/{id}/_unmute_all` +* `POST /api/alerts/alert/{id}/_update_api_key` has been replaced by `POST /api/alerting/rule/{id}/_update_api_key` +* `GET /api/alerts/{id}/_instance_summary` has been deprecated without replacement. Will be removed in v9.0.0 +* `GET /api/alerts/{id}/state` has been deprecated without replacement. Will be removed in v9.0.0 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/alerts/{id}/_instance_summary` endpoint. +Remove references to `GET /api/alerts/{id}/state` endpoint. +Replace references to endpoints listed as deprecated by it's replacement. See `Details` section. +The updated APIs can be found in {api-kibana}/group/endpoint-alerting +==== + +.Removed legacy cases endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `GET /api/cases/status` has been deprecated with no replacement. Deleted in v9.0.0 +* `GET /api/cases/{case_id}/comments` has been replaced by `GET /api/cases/{case_id}/comments/_find` released in v7.13 +* `GET /api/cases//user_actions` has been replaced by `GET /api/cases//user_actions/_find` released in v8.7 +* `includeComments` parameter in `GET /api/cases/{case_id}` has been deprecated. Use `GET /api/cases/{case_id}/comments/_find` instead, released in v7.13 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/cases/status` endpoint. +Replace references to deprecated endpoints with the replacements listed in the breaking change details. +==== + [discrete] .Removed all security v1 endpoints (9.0.0) [%collapsible] diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 8e8ee80ff81be..00841c869ef4f 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -470,6 +470,10 @@ The plugin exposes the static DefaultEditorController class to consume. |WARNING: Missing README. +|{kib-repo}blob/{branch}/x-pack/plugins/asset_inventory/README.md[assetInventory] +|Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments. + + |{kib-repo}blob/{branch}/x-pack/plugins/banners/README.md[banners] |Allow to add a header banner that will be displayed on every page of the Kibana application diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index f6b8e6844ce04..fde70b5ffca0e 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -208,10 +208,6 @@ The default refresh interval for the time filter. Example: [[timepicker-timedefaults]]`timepicker:timeDefaults`:: The default selection in the time filter. -[[truncate-maxheight]]`truncate:maxHeight`:: -deprecated:[8.16.0]The maximum height that a cell occupies in a table. Set to 0 to disable -truncation. - [[enableESQL]]`enableESQL`:: This setting enables ES|QL in Kibana. @@ -340,14 +336,6 @@ Hides the "Time" column in *Discover* and in all saved searches on dashboards. Highlights results in *Discover* and saved searches on dashboards. Highlighting slows requests when working on big documents. -[[doctable-legacy]]`doc_table:legacy`:: -deprecated:[8.15.0] Controls the way the document table looks and works. -To use the new *Document Explorer* instead of the classic view, turn off this option. -The *Document Explorer* offers better data sorting, resizable columns, and a full screen view. - -[[truncate-max-height]]`truncate:maxHeight`:: -The maximum height that a cell in a table can occupy. To disable truncation, set to 0. - [float] [[kibana-ml-settings]] diff --git a/docs/maps/asset-tracking-tutorial.asciidoc b/docs/maps/asset-tracking-tutorial.asciidoc index b1ded453214f6..d7f8497c50b97 100644 --- a/docs/maps/asset-tracking-tutorial.asciidoc +++ b/docs/maps/asset-tracking-tutorial.asciidoc @@ -24,7 +24,7 @@ image::maps/images/asset-tracking-tutorial/construction_zones.png[] [float] === Prerequisites -- If you don’t already have {kib}, set it up with https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[our free trial]. Download the deployment credentials. +- If you don’t already have {kib}, sign up for https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[a free Elastic Cloud trial] and create a hosted deployment. When creating it, download the deployment credentials. - Obtain an API key for https://developer.trimet.org/[TriMet web services] at https://developer.trimet.org/appid/registration/. - {fleet-guide}/fleet-overview.html[Fleet] is enabled on your cluster, and one or more {fleet-guide}/elastic-agent-installation.html[{agent}s] is enrolled. diff --git a/docs/search/images/inference-endpoints-ui.png b/docs/search/images/inference-endpoints-ui.png new file mode 100644 index 0000000000000..a4e091b6091f9 Binary files /dev/null and b/docs/search/images/inference-endpoints-ui.png differ diff --git a/docs/search/inference-endpoints/index.asciidoc b/docs/search/inference-endpoints/index.asciidoc index 30ead243d1510..d547e00dd5b50 100644 --- a/docs/search/inference-endpoints/index.asciidoc +++ b/docs/search/inference-endpoints/index.asciidoc @@ -2,4 +2,14 @@ [[inference-endpoints]] == Inference endpoints UI -(coming in 8.16.0) \ No newline at end of file +Inference endpoints streamline the deployment and management of machine learning models in +{es}. The *Inference endpoints* page in {kib} provides an interface for displaying inference +endpoints that have been created using the {ref}/put-inference-api.html[Inference API]. + +[role="screenshot"] +image::images/inference-endpoints-ui.png[Inference endpoints UI] + +Available actions: + +* Copy the inference endpoint ID +* Delete endpoints \ No newline at end of file diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 0f4987822dc32..6bd7eb1e76345 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -577,12 +577,6 @@ For a <>, <> - `xpack.alerting.cancelAlertsOnRuleTimeout` {ess-icon}:: Specifies whether to skip writing alerts and scheduling actions if rule processing was cancelled due to a timeout. Default: `true`. This setting can be diff --git a/docs/settings/task-manager-settings.asciidoc b/docs/settings/task-manager-settings.asciidoc index 1311974e27342..7200500a2bf06 100644 --- a/docs/settings/task-manager-settings.asciidoc +++ b/docs/settings/task-manager-settings.asciidoc @@ -17,7 +17,7 @@ Task Manager runs background tasks by polling for work on an interval. You can The maximum number of times a task will be attempted before being abandoned as failed. Defaults to 3. `xpack.task_manager.poll_interval`:: -How often, in milliseconds, the task manager will look for more work. Defaults to 3000 and cannot be lower than 100. +How often, in milliseconds, the task manager will look for more work. Defaults to 500 and cannot be lower than 100. `xpack.task_manager.request_capacity`:: How many requests can Task Manager buffer before it rejects new requests. Defaults to 1000. diff --git a/docs/setup/install.asciidoc b/docs/setup/install.asciidoc index 83e6b6f26b335..c3bb456721b9b 100644 --- a/docs/setup/install.asciidoc +++ b/docs/setup/install.asciidoc @@ -2,9 +2,9 @@ == Install {kib} [float] -=== Hosted {kib} +=== {kib} on Elastic Cloud -If you are running our hosted Elasticsearch Service on Elastic Cloud, you access Kibana with a single click. (You can {ess-trial}[sign up for a free trial] and start exploring data in minutes.) +If you are using Elastic Cloud, you access Kibana with a single click. (You can {ess-trial}[sign up for a free trial] and start exploring data in minutes.) [float] === Install {kib} yourself diff --git a/docs/setup/secure-settings.asciidoc b/docs/setup/secure-settings.asciidoc index 63d0465db9a0a..4dc80b097b694 100644 --- a/docs/setup/secure-settings.asciidoc +++ b/docs/setup/secure-settings.asciidoc @@ -8,8 +8,8 @@ keystore, and the `kibana-keystore` tool to manage the settings in the keystore. [NOTE] ==== * Run all commands as the user who runs {kib}. -* Only the settings with the `(Secure)` qualifier should be stored in the keystore. - Unsupported, extraneous or invalid JSON-string settings cause {kib} to fail to start up. +* Any valid {kib} setting can be stored in the keystore securely. + Unsupported, extraneous or invalid settings will cause {kib} to fail to start up. ==== [float] diff --git a/docs/upgrade-notes.asciidoc b/docs/upgrade-notes.asciidoc index 92c53ae4613c5..236d768b16d4e 100644 --- a/docs/upgrade-notes.asciidoc +++ b/docs/upgrade-notes.asciidoc @@ -50,18 +50,51 @@ For Elastic Security solution release information, refer to {security-guide}/rel [discrete] -[[breaking-201004]] -.[Cases] Legacy deprecations (9.0.0) +[[breaking-201550]] +.Removed legacy alerting endpoints (9.0.0) [%collapsible] ==== *Details* + -`GET /api/cases/status` has been deprecated with no replacement. Deleted in v9.0.0 +-- +* `POST /api/alerts/alert/{id?}` has been replaced by `POST /api/alerting/rule/{id?}` +* `GET /api/alerts/alert/{id}` has been replaced by `GET /api/alerting/rule/{id}` +* `PUT /api/alerts/alert/{id}` has been replaced by `PUT /api/alerting/rule/rule/{id}` +* `DELETE: /api/alerts/alert/{id}` has been replaced by `DELETE /api/alerting/rule/{id}` +* `POST /api/alerts/alert/{id}/_disable` has been replaced by `POST /api/alerting/rule/{id}/_disable` +* `POST /api/alerts/alert/{id}/_enable` has been replaced by `POST /api/alerting/rule/{id}/_enable` +* `GET /api/alerts/_find` has been replaced by `GET /api/alerting/rules/_find` +* `GET /api/alerts/_health` has been replaced by `GET /api/alerting/rule/_health` +* `GET /api/alerts/list_alert_types` has been replaced by `GET /api/alerting/rule_types` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_unmute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute` +* `POST /api/alerts/alert/{id}/_mute_all` has been replaced by `POST /api/alerting/rule/{id}/_mute_all` +* `POST /api/alerts/alert/{id}/_unmute_all` has been replaced by `POST /api/alerting/rule/{id}/_unmute_all` +* `POST /api/alerts/alert/{id}/_update_api_key` has been replaced by `POST /api/alerting/rule/{id}/_update_api_key` +* `GET /api/alerts/{id}/_instance_summary` has been deprecated without replacement. Will be removed in v9.0.0 +* `GET /api/alerts/{id}/state` has been deprecated without replacement. Will be removed in v9.0.0 +-- -`GET /api/cases/{case_id}/comments` has been replaced by `GET /api/cases/{case_id}/comments/_find` released in v7.13 +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 -`GET /api/cases//user_actions` has been replaced by `GET /api/cases//user_actions/_find` released in v8.7 +*Action* + +Remove references to `GET /api/alerts/{id}/_instance_summary` endpoint. +Remove references to `GET /api/alerts/{id}/state` endpoint. +Replace references to endpoints listed as deprecated by it's replacement. See `Details` section. +The updated APIs can be found here https://www.elastic.co/docs/api/doc/kibana/v8/group/endpoint-alerting +==== -`includeComments` parameter in `GET /api/cases/{case_id}` has been deprecated. Use `GET /api/cases/{case_id}/comments/_find` instead, released in v7.13 +[[breaking-201004]] +.Removed legacy cases endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `GET /api/cases/status` has been deprecated with no replacement. Deleted in v9.0.0 +* `GET /api/cases/{case_id}/comments` has been replaced by `GET /api/cases/{case_id}/comments/_find` released in v7.13 +* `GET /api/cases//user_actions` has been replaced by `GET /api/cases//user_actions/_find` released in v8.7 +* `includeComments` parameter in `GET /api/cases/{case_id}` has been deprecated. Use `GET /api/cases/{case_id}/comments/_find` instead, released in v7.13 +-- *Impact* + Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 diff --git a/docs/user/alerting/troubleshooting/testing-connectors.asciidoc b/docs/user/alerting/troubleshooting/testing-connectors.asciidoc index 3170ec27ccdb9..7d505f6eab80a 100644 --- a/docs/user/alerting/troubleshooting/testing-connectors.asciidoc +++ b/docs/user/alerting/troubleshooting/testing-connectors.asciidoc @@ -18,7 +18,7 @@ image::user/alerting/images/teams-connector-test.png[Five clauses define the con ==== experimental[] Troubleshooting connectors with the `kbn-action` tool You can run an email action via https://github.com/pmuellr/kbn-action[kbn-action]. -In this example, it is a Cloud deployment of the {stack}: +In this example, it is a Cloud hosted deployment of the {stack}: [source, txt] -------------------------------------------------- diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index ed4fef61026f5..4425cc45d9b4d 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -72,7 +72,7 @@ NOTE: You can use the *Copy POST URL* option instead to generate the report from You can then download it from that message, or go to the *Stack Management > Reporting* page to view and access all of your reports. -NOTE: In "stateful" deployments, reports are stored in {es} and managed by the `kibana-reporting` {ilm} +NOTE: In self-managed and Cloud hosted deployments, reports are stored in {es} and managed by the `kibana-reporting` {ilm} ({ilm-init}) policy. By default, the policy stores reports forever. To learn more about {ilm-init} policies, refer to the {es} {ref}/index-lifecycle-management.html[{ilm-init} documentation]. @@ -108,7 +108,7 @@ Create and share JSON files for workpads. * *Embed code* — Embed fully interactive dashboards as an iframe on web pages. [[reporting-on-cloud-resource-requirements]] -NOTE: For Elastic Cloud deployments, {kib} instances require a minimum of 2GB RAM to generate PDF or PNG reports. To +NOTE: For Elastic Cloud hosted deployments, {kib} instances require a minimum of 2GB RAM to generate PDF or PNG reports. To change {kib} sizing, {ess-console}[edit the deployment]. diff --git a/examples/grid_example/public/app.tsx b/examples/grid_example/public/app.tsx index f144daa29f1ab..1a44d2cb4f8c1 100644 --- a/examples/grid_example/public/app.tsx +++ b/examples/grid_example/public/app.tsx @@ -23,10 +23,12 @@ import { EuiPageTemplate, EuiProvider, EuiSpacer, + EuiButtonGroup, + EuiButtonIcon, } from '@elastic/eui'; import { AppMountParameters } from '@kbn/core-application-browser'; import { CoreStart } from '@kbn/core-lifecycle-browser'; -import { GridLayout, GridLayoutData } from '@kbn/grid-layout'; +import { GridLayout, GridLayoutData, GridAccessMode } from '@kbn/grid-layout'; import { i18n } from '@kbn/i18n'; import { getPanelId } from './get_panel_id'; @@ -46,6 +48,8 @@ const DASHBOARD_GRID_COLUMN_COUNT = 48; export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { const savedState = useRef(getSerializedDashboardState()); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const [expandedPanelId, setExpandedPanelId] = useState(); + const [accessMode, setAccessMode] = useState('EDIT'); const [currentLayout, setCurrentLayout] = useState( dashboardInputToGridLayout(savedState.current) ); @@ -72,6 +76,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
{id}
{ + setExpandedPanelId(undefined); mockDashboardApi.removePanel(id); }} > @@ -81,6 +86,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { { + setExpandedPanelId(undefined); const newPanelId = await getPanelId({ coreStart, suggestion: id, @@ -92,10 +98,25 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { defaultMessage: 'Replace panel', })} + setExpandedPanelId((expandedId) => (expandedId ? undefined : id))} + aria-label={ + expandedPanelId + ? i18n.translate('examples.gridExample.minimizePanel', { + defaultMessage: 'Minimize panel {id}', + values: { id }, + }) + : i18n.translate('examples.gridExample.maximizePanel', { + defaultMessage: 'Maximize panel {id}', + values: { id }, + }) + } + /> ); }, - [coreStart, mockDashboardApi] + [coreStart, mockDashboardApi, setExpandedPanelId, expandedPanelId] ); return ( @@ -107,7 +128,12 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { defaultMessage: 'Grid Layout Example', })} /> - + { { + setExpandedPanelId(undefined); const panelId = await getPanelId({ coreStart, suggestion: uuidv4(), @@ -146,6 +173,34 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { + + { + setAccessMode(id as GridAccessMode); + }} + /> + {hasUnsavedChanges && ( @@ -190,6 +245,8 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { security: - apiKeyAuth: [] tags: @@ -7560,42 +7560,6 @@ paths: tags: - Security Entity Analytics API x-beta: true - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/Security_Entity_Analytics_API_IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API - x-beta: true /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -7749,6 +7713,12 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: If true returns a detailed status of the engine including all it's components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -7758,10 +7728,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + allOf: + - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/Security_Entity_Analytics_API_StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -9648,8 +9628,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -10180,8 +10158,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -10362,8 +10338,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -10916,8 +10890,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -11450,8 +11422,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -11981,8 +11951,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -12163,8 +12131,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -12717,8 +12683,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -14268,6 +14232,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -14735,6 +14700,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -15079,6 +15045,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -32247,8 +32214,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: exportSavedObjectsDefault parameters: - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' @@ -32307,8 +32272,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: importSavedObjectsDefault parameters: - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' @@ -34512,8 +34475,6 @@ paths: schema: $ref: '#/components/schemas/SLOs_409_response' description: Conflict - The SLO id already exists - servers: - - url: https://localhost:5601 summary: Create an SLO tags: - slo @@ -34553,8 +34514,6 @@ paths: schema: $ref: '#/components/schemas/SLOs_403_response' description: Unauthorized response - servers: - - url: https://localhost:5601 summary: Batch delete rollup and summary data tags: - slo @@ -45755,6 +45714,47 @@ components: $ref: '#/components/schemas/Security_Entity_Analytics_API_AssetCriticalityLevel' required: - criticality_level + Security_Entity_Analytics_API_EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + Security_Entity_Analytics_API_EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentResource' + required: + - id + - installed + - resource Security_Entity_Analytics_API_EngineDataviewUpdateResult: type: object properties: @@ -48650,19 +48650,23 @@ components: properties: frequency: default: 1m - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. example: 5m type: string preventInitialBackfill: default: false - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. example: true type: boolean syncDelay: default: 1m - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. example: 5m type: string + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + example: event.ingested + type: string title: Settings type: object SLOs_slo_definition_response: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 208bced5d70f6..0abbcc4b4a102 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -10445,41 +10445,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/Security_Entity_Analytics_API_IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -10630,6 +10595,12 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: If true returns a detailed status of the engine including all it's components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -10639,10 +10610,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + allOf: + - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/Security_Entity_Analytics_API_StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -12508,8 +12489,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -13039,8 +13018,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -13221,8 +13198,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -13774,8 +13749,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -14307,8 +14280,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -14837,8 +14808,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -15019,8 +14988,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -15572,8 +15539,6 @@ paths: maximum: 65353 minimum: 0 type: number - required: - - enabled monitoring_output_id: nullable: true type: string @@ -17115,6 +17080,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -17579,6 +17545,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -17922,6 +17889,7 @@ paths: type: array upgrade_details: additionalProperties: false + nullable: true type: object properties: action_id: @@ -35089,7 +35057,7 @@ paths: schema: type: object description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -35121,7 +35089,7 @@ paths: schema: type: object description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -35140,8 +35108,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: exportSavedObjectsDefault parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -35301,8 +35267,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: importSavedObjectsDefault parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -35399,8 +35363,6 @@ paths: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: resolveImportErrors parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -53478,6 +53440,47 @@ components: $ref: '#/components/schemas/Security_Entity_Analytics_API_AssetCriticalityLevel' required: - criticality_level + Security_Entity_Analytics_API_EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + Security_Entity_Analytics_API_EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentResource' + required: + - id + - installed + - resource Security_Entity_Analytics_API_EngineDataviewUpdateResult: type: object properties: @@ -56355,19 +56358,23 @@ components: properties: frequency: default: 1m - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. example: 5m type: string preventInitialBackfill: default: false - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. example: true type: boolean syncDelay: default: 1m - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. example: 5m type: string + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + example: event.ingested + type: string title: Settings type: object SLOs_slo_definition_response: diff --git a/oas_docs/overlays/kibana.overlays.serverless.yaml b/oas_docs/overlays/kibana.overlays.serverless.yaml index 1054f774fe11e..36efbe18e9403 100644 --- a/oas_docs/overlays/kibana.overlays.serverless.yaml +++ b/oas_docs/overlays/kibana.overlays.serverless.yaml @@ -14,7 +14,7 @@ actions: - url: https://{kibana_url} variables: kibana_url: - default: localhost:5601 + default: # Mark all operations as beta - target: "$.paths[*]['get','put','post','delete','options','head','patch','trace']" description: Add x-beta diff --git a/oas_docs/overlays/kibana.overlays.yaml b/oas_docs/overlays/kibana.overlays.yaml index ed41f56088bf8..666cba540a658 100644 --- a/oas_docs/overlays/kibana.overlays.yaml +++ b/oas_docs/overlays/kibana.overlays.yaml @@ -4,6 +4,17 @@ info: title: Overlays for the Kibana API document version: 0.0.1 actions: +# Clean up server definitions + - target: '$.servers.*' + description: Remove all servers so we can add our own. + remove: true + - target: '$.servers' + description: Add server into the now empty server array. + update: + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 # Add an introduction to spaces - target: '$' description: Add an extra page about spaces diff --git a/oas_docs/package-lock.json b/oas_docs/package-lock.json index 70fff86254f65..ab921922f0d15 100644 --- a/oas_docs/package-lock.json +++ b/oas_docs/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@redocly/cli": "^1.25.11", + "@redocly/cli": "^1.25.14", "bump-cli": "^2.8.4" } }, @@ -515,12 +515,12 @@ } }, "node_modules/@redocly/cli": { - "version": "1.25.11", - "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.25.11.tgz", - "integrity": "sha512-dttBsmLnnbTlJCTa+s7Sy+qtXDq692n7Ru3nUUIHp9XdCbhXIHWhpc8uAl+GmR4MGbVe8ohATl3J+zX3aFy82A==", + "version": "1.25.15", + "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.25.15.tgz", + "integrity": "sha512-ZD743CJX4FpMJvGNE9Cm3gNn8LNRzRjyrYNVPi1C4iIEtrFkr5Zq791qv6gUFehWns71svbVyzWD9ftVTdfqYg==", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "1.25.11", + "@redocly/openapi-core": "1.25.15", "abort-controller": "^3.0.0", "chokidar": "^3.5.1", "colorette": "^1.2.0", @@ -550,17 +550,19 @@ } }, "node_modules/@redocly/config": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.16.0.tgz", - "integrity": "sha512-t9jnODbUcuANRSl/K4L9nb12V+U5acIHnVSl26NWrtSdDZVtoqUXk2yGFPZzohYf62cCfEQUT8ouJ3bhPfpnJg==" + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.17.1.tgz", + "integrity": "sha512-CEmvaJuG7pm2ylQg53emPmtgm4nW2nxBgwXzbVEHpGas/lGnMyN8Zlkgiz6rPw0unASg6VW3wlz27SOL5XFHYQ==", + "license": "MIT" }, "node_modules/@redocly/openapi-core": { - "version": "1.25.11", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.11.tgz", - "integrity": "sha512-bH+a8izQz4fnKROKoX3bEU8sQ9rjvEIZOqU6qTmxlhOJ0NsKa5e+LmU18SV0oFeg5YhWQhhEDihXkvKJ1wMMNQ==", + "version": "1.25.15", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.15.tgz", + "integrity": "sha512-/dpr5zpGj2t1Bf7EIXEboRZm1hsJZBQfv3Q1pkivtdAEg3if2khv+b9gY68aquC6cM/2aQY2kMLy8LlY2tn+Og==", + "license": "MIT", "dependencies": { "@redocly/ajv": "^8.11.2", - "@redocly/config": "^0.16.0", + "@redocly/config": "^0.17.0", "colorette": "^1.2.0", "https-proxy-agent": "^7.0.4", "js-levenshtein": "^1.1.6", diff --git a/oas_docs/package.json b/oas_docs/package.json index 3f6cae5c044b3..9510dc4d31dc7 100644 --- a/oas_docs/package.json +++ b/oas_docs/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "bump-cli": "^2.8.4", - "@redocly/cli": "^1.25.11" + "@redocly/cli": "^1.25.14" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/package.json b/package.json index 05d25d4fd6140..e96dae9d0bd64 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", "@xstate5/react/**/xstate": "^5.18.1", - "globby/fast-glob": "^3.2.11" + "globby/fast-glob": "^3.3.2" }, "dependencies": { "@appland/sql-parser": "^1.5.1", @@ -111,7 +111,7 @@ "@elastic/apm-rum": "^5.16.1", "@elastic/apm-rum-core": "^5.21.1", "@elastic/apm-rum-react": "^2.0.3", - "@elastic/charts": "68.0.2", + "@elastic/charts": "68.0.3", "@elastic/datemath": "5.0.3", "@elastic/ebt": "^1.1.1", "@elastic/ecs": "^8.11.1", @@ -191,6 +191,7 @@ "@kbn/apm-utils": "link:packages/kbn-apm-utils", "@kbn/app-link-test-plugin": "link:test/plugin_functional/plugins/app_link_test", "@kbn/application-usage-test-plugin": "link:x-pack/test/usage_collection/plugins/application_usage_test", + "@kbn/asset-inventory-plugin": "link:x-pack/plugins/asset_inventory", "@kbn/audit-log-plugin": "link:x-pack/test/security_api_integration/plugins/audit_log", "@kbn/avc-banner": "link:packages/kbn-avc-banner", "@kbn/banners-plugin": "link:x-pack/plugins/banners", @@ -758,6 +759,7 @@ "@kbn/resizable-layout-examples-plugin": "link:examples/resizable_layout_examples", "@kbn/resolver-test-plugin": "link:x-pack/test/plugin_functional/plugins/resolver_test", "@kbn/response-ops-feature-flag-service": "link:packages/response-ops/feature_flag_service", + "@kbn/response-ops-rule-form": "link:packages/response-ops/rule_form", "@kbn/response-ops-rule-params": "link:packages/response-ops/rule_params", "@kbn/response-stream-plugin": "link:examples/response_stream", "@kbn/rison": "link:packages/kbn-rison", @@ -785,6 +787,7 @@ "@kbn/saved-objects-settings": "link:packages/kbn-saved-objects-settings", "@kbn/saved-objects-tagging-oss-plugin": "link:src/plugins/saved_objects_tagging_oss", "@kbn/saved-objects-tagging-plugin": "link:x-pack/plugins/saved_objects_tagging", + "@kbn/saved-search-component": "link:packages/kbn-saved-search-component", "@kbn/saved-search-plugin": "link:src/plugins/saved_search", "@kbn/screenshot-mode-example-plugin": "link:examples/screenshot_mode_example", "@kbn/screenshot-mode-plugin": "link:src/plugins/screenshot_mode", @@ -1029,7 +1032,7 @@ "@langchain/google-vertexai": "^0.1.0", "@langchain/langgraph": "0.2.19", "@langchain/openai": "^0.3.11", - "@langtrase/trace-attributes": "^3.0.8", + "@langtrase/trace-attributes": "^7.5.0", "@launchdarkly/node-server-sdk": "^9.7.2", "@launchdarkly/openfeature-node-server": "^1.0.0", "@loaders.gl/core": "^3.4.7", @@ -1056,12 +1059,12 @@ "@reduxjs/toolkit": "1.9.7", "@slack/webhook": "^7.0.1", "@smithy/eventstream-codec": "^3.1.1", - "@smithy/eventstream-serde-node": "^3.0.3", + "@smithy/eventstream-serde-node": "^3.0.12", "@smithy/middleware-stack": "^3.0.10", "@smithy/node-http-handler": "^3.3.1", "@smithy/protocol-http": "^4.1.7", - "@smithy/signature-v4": "^3.1.1", - "@smithy/types": "^3.2.0", + "@smithy/signature-v4": "^4.2.3", + "@smithy/types": "^3.7.1", "@smithy/util-utf8": "^3.0.0", "@tanstack/react-query": "^4.29.12", "@tanstack/react-query-devtools": "^4.29.12", @@ -1080,12 +1083,12 @@ "@xyflow/react": "^12.3.5", "adm-zip": "^0.5.9", "ai": "^2.2.33", - "ajv": "^8.12.0", + "ajv": "^8.17.1", "ansi-regex": "^6.1.0", "antlr4": "^4.13.1-patch-1", "archiver": "^7.0.1", "async": "^3.2.3", - "aws4": "^1.12.0", + "aws4": "^1.13.2", "axios": "^1.7.4", "base64-js": "^1.3.1", "bitmap-sdf": "^1.0.3", @@ -1128,7 +1131,7 @@ "dotenv": "^16.4.5", "elastic-apm-node": "^4.8.1", "email-addresses": "^5.0.0", - "eventsource-parser": "^1.1.1", + "eventsource-parser": "^3.0.0", "execa": "^5.1.1", "expiry-js": "0.1.7", "exponential-backoff": "^3.1.1", @@ -1146,7 +1149,7 @@ "getos": "^3.1.0", "globby": "^11.1.0", "google-auth-library": "^9.10.0", - "gpt-tokenizer": "^2.1.2", + "gpt-tokenizer": "^2.6.2", "handlebars": "4.7.8", "he": "^1.2.0", "history": "^4.9.0", @@ -1174,7 +1177,7 @@ "jsts": "^1.6.2", "kea": "^2.6.0", "langchain": "^0.3.5", - "langsmith": "^0.2.3", + "langsmith": "^0.2.5", "launchdarkly-js-client-sdk": "^3.5.0", "load-json-file": "^6.2.0", "lodash": "^4.17.21", @@ -1203,7 +1206,7 @@ "nunjucks": "^3.2.4", "object-hash": "^1.3.1", "object-path-immutable": "^3.1.1", - "openai": "^4.68.0", + "openai": "^4.72.0", "openpgp": "5.10.1", "ora": "^4.0.4", "p-limit": "^3.0.1", @@ -1430,6 +1433,7 @@ "@kbn/core-ui-settings-server-mocks": "link:packages/core/ui-settings/core-ui-settings-server-mocks", "@kbn/core-usage-data-server-mocks": "link:packages/core/usage-data/core-usage-data-server-mocks", "@kbn/cypress-config": "link:packages/kbn-cypress-config", + "@kbn/dependency-ownership": "link:packages/kbn-dependency-ownership", "@kbn/dependency-usage": "link:packages/kbn-dependency-usage", "@kbn/dev-cli-errors": "link:packages/kbn-dev-cli-errors", "@kbn/dev-cli-runner": "link:packages/kbn-dev-cli-runner", @@ -1512,8 +1516,8 @@ "@mswjs/http-middleware": "^0.10.1", "@octokit/rest": "^17.11.2", "@parcel/watcher": "^2.1.0", - "@playwright/test": "=1.46.0", - "@redocly/cli": "^1.25.11", + "@playwright/test": "1.49.0", + "@redocly/cli": "^1.25.14", "@statoscope/webpack-plugin": "^5.28.2", "@storybook/addon-a11y": "^6.5.16", "@storybook/addon-actions": "^6.5.16", @@ -1569,7 +1573,6 @@ "@types/eslint": "^8.44.2", "@types/express": "^4.17.21", "@types/extract-zip": "^1.6.2", - "@types/faker": "^5.1.5", "@types/fetch-mock": "^7.3.1", "@types/file-saver": "^2.0.0", "@types/flot": "^0.0.31", @@ -1589,7 +1592,7 @@ "@types/js-search": "^1.4.0", "@types/js-yaml": "^4.0.9", "@types/jsdom": "^20.0.1", - "@types/json-schema": "^7", + "@types/json-schema": "^7.0.15", "@types/json-stable-stringify": "^1.0.32", "@types/json5": "^2.2.0", "@types/jsonwebtoken": "^9.0.0", @@ -1624,7 +1627,7 @@ "@types/picomatch": "^2.3.0", "@types/pidusage": "^2.0.2", "@types/pixelmatch": "^5.2.4", - "@types/pngjs": "^3.4.0", + "@types/pngjs": "^6.0.5", "@types/prop-types": "^15.7.5", "@types/rbush": "^3.0.0", "@types/react": "~18.2.0", @@ -1691,7 +1694,7 @@ "buildkite-test-collector": "^1.7.0", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^131.0.0", + "chromedriver": "^131.0.1", "clarify": "^2.2.0", "clean-webpack-plugin": "^3.0.0", "cli-progress": "^3.12.0", @@ -1738,7 +1741,6 @@ "expect": "^29.7.0", "expose-loader": "^0.7.5", "express": "^4.21.1", - "faker": "^5.1.0", "fetch-mock": "^7.3.9", "file-loader": "^4.2.0", "find-cypress-specs": "^1.41.4", @@ -1790,8 +1792,8 @@ "native-hdr-histogram": "^1.0.0", "nock": "12.0.3", "null-loader": "^3.0.0", - "nyc": "^15.1.0", - "oboe": "^2.1.4", + "nyc": "^17.1.0", + "oboe": "^2.1.7", "openapi-types": "^12.1.3", "p-reflect": "2.1.0", "peggy": "^1.2.0", @@ -1800,9 +1802,9 @@ "pirates": "^4.0.1", "piscina": "^3.2.0", "pixelmatch": "^5.3.0", - "playwright": "=1.46.0", - "playwright-chromium": "=1.46.0", - "pngjs": "^3.4.0", + "playwright": "1.49.0", + "playwright-chromium": "1.49.0", + "pngjs": "^7.0.0", "postcss": "^8.4.31", "postcss-loader": "^4.2.0", "postcss-prefix-selector": "^1.16.0", @@ -1818,7 +1820,7 @@ "rxjs-marbles": "^7.0.1", "sass-embedded": "^1.78.0", "sass-loader": "^10.5.1", - "selenium-webdriver": "^4.26.0", + "selenium-webdriver": "^4.27.0", "sharp": "0.32.6", "simple-git": "^3.16.0", "sinon": "^7.4.2", @@ -1828,12 +1830,12 @@ "style-loader": "^1.1.3", "stylelint": "^14.9.1", "stylelint-scss": "^4.3.0", - "superagent": "^9.0.2", + "superagent": "^10.1.1", "supertest": "^7.0.0", "svgo": "^2.8.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1", - "table": "^6.8.1", + "table": "^6.8.2", "tape": "^5.0.1", "terser": "^5.36.0", "terser-webpack-plugin": "^4.2.3", @@ -1856,7 +1858,7 @@ "webpack-sources": "^1.4.1", "webpack-visualizer-plugin2": "^1.1.0", "xml-crypto": "^6.0.0", - "xmlbuilder": "13.0.2", + "xmlbuilder": "15.1.1", "yargs": "^15.4.1", "yarn-deduplicate": "^6.0.2", "zod-to-json-schema": "^3.23.0" diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts index 9fe591d9c5214..f8a50d39271d6 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts @@ -19,8 +19,10 @@ export const registerMigrateRoute = ( { path: '/_migrate', validate: false, - options: { - tags: ['access:migrateSavedObjects'], + security: { + authz: { + requiredPrivileges: ['migrateSavedObjects'], + }, }, }, catchAndReturnBoomErrors(async (context, req, res) => { diff --git a/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts b/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts index a29875a733d68..cb2930f5d4676 100644 --- a/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts +++ b/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts @@ -75,8 +75,11 @@ export interface SavedObjectsType { */ mappings: SavedObjectsTypeMappingDefinition; /** - * An optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of {@link SavedObjectMigrationFn | migrations} to be used to migrate the type. - * @deprecated Use {@link SavedObjectsType.modelVersions | modelVersions} instead. + * An optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of + * {@link SavedObjectMigrationFn | migrations} to be used to migrate the type. + * + * @deprecated Use {@link SavedObjectsType.modelVersions | modelVersions} for all future migrations instead. We have no plans + * to remove legacy migrations at this point, so there's no need to migrate existing migrations to model versions. */ migrations?: SavedObjectMigrationMap | (() => SavedObjectMigrationMap); /** @@ -89,8 +92,8 @@ export interface SavedObjectsType { */ schemas?: SavedObjectsValidationMap | (() => SavedObjectsValidationMap); /** - * If defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to this - * version. + * If defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to + * this version. * * Requirements: * diff --git a/packages/core/saved-objects/docs/openapi/bundled.json b/packages/core/saved-objects/docs/openapi/bundled.json index 45cfdd7fa5055..c445332816661 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.json +++ b/packages/core/saved-objects/docs/openapi/bundled.json @@ -380,7 +380,7 @@ "post": { "summary": "Export saved objects", "operationId": "exportSavedObjectsDefault", - "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n", "tags": [ "saved objects" ], @@ -639,7 +639,7 @@ "post": { "summary": "Import saved objects", "operationId": "importSavedObjectsDefault", - "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n", "tags": [ "saved objects" ], @@ -759,7 +759,7 @@ "post": { "summary": "Resolve import errors", "operationId": "resolveImportErrors", - "description": "To resolve errors from the Import objects API, you can:\n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "To resolve errors from the Import objects API, you can:\n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n", "tags": [ "saved objects" ], @@ -1423,4 +1423,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/core/saved-objects/docs/openapi/bundled.yaml b/packages/core/saved-objects/docs/openapi/bundled.yaml index 9b5aad6e54958..b62424c10a7fe 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled.yaml @@ -216,7 +216,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -248,7 +248,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -270,8 +270,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -431,8 +429,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -529,8 +525,6 @@ paths: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/bundled_serverless.json b/packages/core/saved-objects/docs/openapi/bundled_serverless.json index 67b8a710b5bcd..b225e95b14739 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.json +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.json @@ -34,7 +34,7 @@ "post": { "summary": "Export saved objects", "operationId": "exportSavedObjectsDefault", - "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n", "tags": [ "saved objects" ], @@ -124,7 +124,7 @@ "post": { "summary": "Import saved objects", "operationId": "importSavedObjectsDefault", - "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n", "tags": [ "saved objects" ], @@ -358,4 +358,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml b/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml index b874f0e32361b..d6775921a3080 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml @@ -37,8 +37,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -96,8 +94,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml index 93224e4d243b3..fd9c248056164 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml @@ -8,8 +8,6 @@ post: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml index 3f27987f779f7..7bd9b6f801c49 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml @@ -4,8 +4,6 @@ post: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml index bfca82dbe7274..c6d2b23ce012d 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml @@ -7,8 +7,6 @@ post: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/kbn-alerting-types/search_strategy_types.ts b/packages/kbn-alerting-types/search_strategy_types.ts index 797ca82294b8a..9df72e4fa7886 100644 --- a/packages/kbn-alerting-types/search_strategy_types.ts +++ b/packages/kbn-alerting-types/search_strategy_types.ts @@ -8,7 +8,6 @@ */ import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/search-types'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { MappingRuntimeFields, QueryDslFieldAndFormat, @@ -18,7 +17,8 @@ import type { import type { Alert } from './alert_type'; export type RuleRegistrySearchRequest = IEsSearchRequest & { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; fields?: QueryDslFieldAndFormat[]; query?: Pick; sort?: SortCombinations[]; diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts new file mode 100644 index 0000000000000..2f08e082aebea --- /dev/null +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +// ---------------------------------- WARNING ---------------------------------- +// this file was generated, and should not be edited by hand +// ---------------------------------- WARNING ---------------------------------- +import * as rt from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { AlertSchema } from './alert_schema'; +import { EcsSchema } from './ecs_schema'; +const ISO_DATE_PATTERN = /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/; +export const IsoDateString = new rt.Type( + 'IsoDateString', + rt.string.is, + (input, context): Either => { + if (typeof input === 'string' && ISO_DATE_PATTERN.test(input)) { + return rt.success(input); + } else { + return rt.failure(input, context); + } + }, + rt.identity +); +export type IsoDateStringC = typeof IsoDateString; +export const schemaUnknown = rt.unknown; +export const schemaUnknownArray = rt.array(rt.unknown); +export const schemaString = rt.string; +export const schemaStringArray = rt.array(schemaString); +export const schemaNumber = rt.number; +export const schemaNumberArray = rt.array(schemaNumber); +export const schemaDate = rt.union([IsoDateString, schemaNumber]); +export const schemaDateArray = rt.array(schemaDate); +export const schemaDateRange = rt.partial({ + gte: schemaDate, + lte: schemaDate, +}); +export const schemaDateRangeArray = rt.array(schemaDateRange); +export const schemaStringOrNumber = rt.union([schemaString, schemaNumber]); +export const schemaStringOrNumberArray = rt.array(schemaStringOrNumber); +export const schemaBoolean = rt.boolean; +export const schemaBooleanArray = rt.array(schemaBoolean); +const schemaGeoPointCoords = rt.type({ + type: schemaString, + coordinates: schemaNumberArray, +}); +const schemaGeoPointString = schemaString; +const schemaGeoPointLatLon = rt.type({ + lat: schemaNumber, + lon: schemaNumber, +}); +const schemaGeoPointLocation = rt.type({ + location: schemaNumberArray, +}); +const schemaGeoPointLocationString = rt.type({ + location: schemaString, +}); +export const schemaGeoPoint = rt.union([ + schemaGeoPointCoords, + schemaGeoPointString, + schemaGeoPointLatLon, + schemaGeoPointLocation, + schemaGeoPointLocationString, +]); +export const schemaGeoPointArray = rt.array(schemaGeoPoint); +// prettier-ignore +const ObservabilityThresholdAlertRequired = rt.type({ +}); +// prettier-ignore +const ObservabilityThresholdAlertOptional = rt.partial({ + 'kibana.alert.context': schemaUnknown, + 'kibana.alert.evaluation.threshold': schemaStringOrNumber, + 'kibana.alert.evaluation.value': schemaStringOrNumber, + 'kibana.alert.evaluation.values': schemaStringOrNumberArray, + 'kibana.alert.group': rt.array( + rt.partial({ + field: schemaStringArray, + value: schemaStringArray, + }) + ), +}); + +// prettier-ignore +export const ObservabilityThresholdAlertSchema = rt.intersection([ObservabilityThresholdAlertRequired, ObservabilityThresholdAlertOptional, AlertSchema, EcsSchema]); +// prettier-ignore +export type ObservabilityThresholdAlert = rt.TypeOf; diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx index 86ae0a54f9224..0137953b2313c 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx @@ -23,7 +23,8 @@ import { groupingSearchResponse } from '../mocks/grouping_query.mock'; import { useAlertsGroupingState } from '../contexts/alerts_grouping_context'; import { I18nProvider } from '@kbn/i18n-react'; import { - mockFeatureIds, + mockRuleTypeIds, + mockConsumers, mockDate, mockGroupingProps, mockGroupingId, @@ -146,7 +147,8 @@ describe('AlertsGrouping', () => { expect.objectContaining({ params: { aggregations: {}, - featureIds: mockFeatureIds, + ruleTypeIds: mockRuleTypeIds, + consumers: mockConsumers, groupByField: 'kibana.alert.rule.name', filters: [ { diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx index d814d70903a5c..5ea010d442145 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx @@ -66,7 +66,7 @@ const AlertsGroupingInternal = ( const { groupingId, services, - featureIds, + ruleTypeIds, defaultGroupingOptions, defaultFilters, globalFilters, @@ -79,7 +79,7 @@ const AlertsGroupingInternal = ( const { grouping, updateGrouping } = useAlertsGroupingState(groupingId); const { dataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts: notifications.toasts, @@ -252,7 +252,7 @@ const typedMemo: (c: T) => T = memo; * * return ( * - * featureIds={[...]} + * ruleTypeIds={[...]} * globalQuery={{ query: ..., language: 'kql' }} * globalFilters={...} * from={...} diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx index 5548c14fcf26f..b908b07caf7a1 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx @@ -55,6 +55,10 @@ const mockGroupingLevelProps: Omit = { describe('AlertsGroupingLevel', () => { let buildEsQuerySpy: jest.SpyInstance; + beforeEach(() => { + jest.clearAllMocks(); + }); + beforeAll(() => { buildEsQuerySpy = jest.spyOn(buildEsQueryModule, 'buildEsQuery'); }); @@ -119,4 +123,58 @@ describe('AlertsGroupingLevel', () => { Object.keys(groupingSearchResponse.aggregations) ); }); + + it('should calls useGetAlertsGroupAggregationsQuery with correct props', () => { + render( + + {() => } + + ); + + expect(mockUseGetAlertsGroupAggregationsQuery.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "enabled": true, + "http": Object { + "get": [MockFunction], + }, + "params": Object { + "aggregations": Object {}, + "consumers": Array [ + "stackAlerts", + ], + "filters": Array [ + Object { + "bool": Object { + "filter": Array [], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "range": Object { + "kibana.alert.time_range": Object { + "gte": "2020-07-07T08:20:18.966Z", + "lte": "2020-07-08T08:20:18.966Z", + }, + }, + }, + ], + "groupByField": "selectedGroup", + "pageIndex": 0, + "pageSize": 10, + "ruleTypeIds": Array [ + ".es-query", + ], + }, + "toasts": Object { + "addDanger": [MockFunction], + }, + }, + ], + ] + `); + }); }); diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx index 7e620276d2e4d..02fd5d33e2379 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx @@ -46,7 +46,8 @@ const DEFAULT_FILTERS: Filter[] = []; const typedMemo: (c: T) => T = memo; export const AlertsGroupingLevel = typedMemo( ({ - featureIds, + ruleTypeIds, + consumers, defaultFilters = DEFAULT_FILTERS, from, getGrouping, @@ -86,7 +87,8 @@ export const AlertsGroupingLevel = typedMemo( const aggregationsQuery = useMemo(() => { return { - featureIds, + ruleTypeIds, + consumers, groupByField: selectedGroup, aggregations: getAggregationsByGroupingField(selectedGroup)?.reduce( (acc, val) => Object.assign(acc, val), @@ -107,12 +109,13 @@ export const AlertsGroupingLevel = typedMemo( pageSize, }; }, [ - featureIds, + consumers, filters, from, getAggregationsByGroupingField, pageIndex, pageSize, + ruleTypeIds, selectedGroup, to, ]); diff --git a/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx b/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx index 925a32fbd9de6..510c7c8fdb896 100644 --- a/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx +++ b/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx @@ -8,12 +8,12 @@ */ import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsGroupingProps } from '../types'; export const mockGroupingId = 'test'; -export const mockFeatureIds = [AlertConsumers.STACK_ALERTS]; +export const mockRuleTypeIds = ['.es-query']; +export const mockConsumers = ['stackAlerts']; export const mockDate = { from: '2020-07-07T08:20:18.966Z', @@ -30,7 +30,8 @@ export const mockOptions = [ export const mockGroupingProps: Omit = { ...mockDate, groupingId: mockGroupingId, - featureIds: mockFeatureIds, + ruleTypeIds: mockRuleTypeIds, + consumers: mockConsumers, defaultGroupingOptions: mockOptions, getAggregationsByGroupingField: () => [], getGroupStats: () => [{ title: 'Stat', component: }], diff --git a/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts b/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts index 8820f884928b7..486771e70a140 100644 --- a/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts +++ b/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts @@ -11,12 +11,12 @@ export const getQuery = ({ selectedGroup, uniqueValue, timeRange, - featureIds, + ruleTypeIds, }: { selectedGroup: string; uniqueValue: string; timeRange: { from: string; to: string }; - featureIds: string[]; + ruleTypeIds: string[]; }) => ({ _source: false, aggs: { @@ -52,7 +52,7 @@ export const getQuery = ({ }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, query: { bool: { filter: [ diff --git a/packages/kbn-alerts-grouping/src/types.ts b/packages/kbn-alerts-grouping/src/types.ts index c6132e94e8729..f1eb9ef00fee8 100644 --- a/packages/kbn-alerts-grouping/src/types.ts +++ b/packages/kbn-alerts-grouping/src/types.ts @@ -8,7 +8,6 @@ */ import type { Filter, Query } from '@kbn/es-query'; -import { ValidFeatureId } from '@kbn/rule-data-utils'; import type { NotificationsStart } from '@kbn/core-notifications-browser'; import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types'; import type { HttpSetup } from '@kbn/core-http-browser'; @@ -63,9 +62,13 @@ export interface AlertsGroupingProps< */ defaultGroupingOptions: GroupOption[]; /** - * The alerting feature ids this grouping covers + * The alerting rule type ids this grouping covers */ - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + /** + * The alerting consumers this grouping covers + */ + consumers?: string[]; /** * Time filter start */ diff --git a/packages/kbn-alerts-ui-shared/index.ts b/packages/kbn-alerts-ui-shared/index.ts index a81942a5f956c..c579fa7ed74fd 100644 --- a/packages/kbn-alerts-ui-shared/index.ts +++ b/packages/kbn-alerts-ui-shared/index.ts @@ -19,3 +19,7 @@ export type { AlertsSearchBarProps } from './src/alerts_search_bar/types'; export * from './src/alert_fields_table'; export * from './src/alert_filter_controls/types'; export * from './src/common/types'; +export * from './src/check_action_type_enabled'; +export * from './src/action_variables'; + +export { useFetchFlappingSettings } from './src/common/hooks/use_fetch_flapping_settings'; diff --git a/packages/kbn-alerts-ui-shared/lib/README.md b/packages/kbn-alerts-ui-shared/lib/README.md new file mode 100644 index 0000000000000..3034f4804bd7c --- /dev/null +++ b/packages/kbn-alerts-ui-shared/lib/README.md @@ -0,0 +1 @@ +Export files in here that are only meant to be used by other KBN packages and not directly imported by plugins. This helps to keep bundle sizes efficient. diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/index.ts b/packages/kbn-alerts-ui-shared/lib/index.ts similarity index 72% rename from src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/index.ts rename to packages/kbn-alerts-ui-shared/lib/index.ts index 3e4ca39981359..808c936f18d27 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/index.ts +++ b/packages/kbn-alerts-ui-shared/lib/index.ts @@ -7,8 +7,5 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DocViewerLegacyTable } from './table'; - -// Required for usage in React.lazy -// eslint-disable-next-line import/no-default-export -export default DocViewerLegacyTable; +export * from '../src/common/type_registry'; +export * from '../src/rule_settings'; diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts index d574aaf9592a9..8411ff911e284 100644 --- a/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts +++ b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts @@ -9,7 +9,7 @@ import { ActionVariables, RuleType } from '@kbn/triggers-actions-ui-types'; import { transformActionVariables } from './transforms'; -import { ALERTING_FEATURE_ID } from '../rule_form'; +import { ALERTING_FEATURE_ID } from '../common/constants'; beforeEach(() => jest.resetAllMocks()); @@ -289,5 +289,6 @@ function getAlertType(actionVariables: ActionVariables): RuleType { producer: ALERTING_FEATURE_ID, minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', }; } diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx index 3c314c62fc28c..6c35234b54006 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { AlertFilterControls, AlertFilterControlsProps } from './alert_filter_controls'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { DEFAULT_CONTROLS } from './constants'; import { useAlertsDataView } from '../common/hooks/use_alerts_data_view'; import { FilterGroup } from './filter_group'; @@ -56,7 +55,7 @@ const ControlGroupRenderer = (() => ( describe('AlertFilterControls', () => { const props: AlertFilterControlsProps = { - featureIds: [AlertConsumers.STACK_ALERTS], + ruleTypeIds: ['.es-query'], defaultControls: DEFAULT_CONTROLS, dataViewSpec: { id: 'alerts-filters-dv', diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx index e8e7e63859250..f64b02e2ee350 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx @@ -12,7 +12,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import type { Filter } from '@kbn/es-query'; import { EuiFlexItem } from '@elastic/eui'; import type { DataViewSpec, DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { HttpStart } from '@kbn/core-http-browser'; import { NotificationsStart } from '@kbn/core-notifications-browser'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -24,12 +23,12 @@ import { FilterControlConfig } from './types'; export type AlertFilterControlsProps = Omit< ComponentProps, - 'dataViewId' | 'defaultControls' | 'featureIds' | 'Storage' + 'dataViewId' | 'defaultControls' | 'ruleTypeIds' | 'Storage' > & { /** - * The feature ids used to get the correct alert data view(s) + * The rule type ids used to get the correct alert data view(s) */ - featureIds?: AlertConsumers[]; + ruleTypeIds?: string[]; /** * An array of default control configurations */ @@ -57,7 +56,7 @@ export type AlertFilterControlsProps = Omit< * * { const { - featureIds = [AlertConsumers.STACK_ALERTS], + ruleTypeIds = [], defaultControls = DEFAULT_CONTROLS, dataViewSpec, onFiltersChange, @@ -96,7 +95,7 @@ export const AlertFilterControls = (props: AlertFilterControlsProps) => { } = props; const [loadingPageFilters, setLoadingPageFilters] = useState(true); const { dataView, isLoading: isLoadingDataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts, @@ -156,7 +155,7 @@ export const AlertFilterControls = (props: AlertFilterControlsProps) => { > = (props) => { ) => { const { - featureIds, dataViewId, onFiltersChange, timeRange, @@ -59,6 +58,7 @@ export const FilterGroup = (props: PropsWithChildren) => { maxControls = Infinity, ControlGroupRenderer, Storage, + ruleTypeIds, storageKey, } = props; @@ -80,8 +80,8 @@ export const FilterGroup = (props: PropsWithChildren) => { const [controlGroup, setControlGroup] = useState(); const localStoragePageFilterKey = useMemo( - () => storageKey ?? `${featureIds.join(',')}.${spaceId}.${URL_PARAM_KEY}`, - [featureIds, spaceId, storageKey] + () => storageKey ?? `${ruleTypeIds.join(',')}.${spaceId}.${URL_PARAM_KEY}`, + [ruleTypeIds, spaceId, storageKey] ); const currentFiltersRef = useRef(); diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts index 19a76c76ff6f8..ed625897a418e 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts @@ -15,7 +15,6 @@ import type { ControlGroupRendererApi, } from '@kbn/controls-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; -import { AlertConsumers } from '@kbn/rule-data-utils'; export type FilterUrlFormat = Record< string, @@ -46,7 +45,7 @@ export interface FilterGroupProps extends Pick ( - - - - - - first - - - - - - - - - - - middle - - - - - - - - - - - - - - last - - - - - - - - - -`; - -exports[`TableHeader without time column renders correctly 1`] = ` - - - - - first - - - - - - - - - - - middle - - - - - - - - - - - - - - last - - - - - - - - - -`; diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx deleted file mode 100644 index 6640164d76d50..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; -import type { DataView } from '@kbn/data-views-plugin/public'; - -export interface ColumnProps { - name: string; - displayName: string; - isSortable: boolean; - isRemoveable: boolean; - colLeftIdx: number; - colRightIdx: number; -} - -/** - * Returns properties necessary to display the time column - * If it's an DataView with timefield, the time column is - * prepended, not moveable and removeable - * @param timeFieldName - */ -export function getTimeColumn(timeFieldName: string): ColumnProps { - return { - name: timeFieldName, - displayName: timeFieldName, - isSortable: true, - isRemoveable: false, - colLeftIdx: -1, - colRightIdx: -1, - }; -} -/** - * A given array of column names returns an array of properties - * necessary to display the columns. If the given dataView - * has a timefield, a time column is prepended - * @param columns - * @param dataView - * @param hideTimeField - * @param isShortDots - */ -export function getDisplayedColumns( - columns: string[], - dataView: DataView, - hideTimeField: boolean, - isShortDots: boolean -) { - if (!Array.isArray(columns) || typeof dataView !== 'object' || !dataView.getFieldByName) { - return []; - } - - const columnProps = - columns.length === 0 - ? [ - { - name: '__document__', - displayName: i18n.translate('discover.docTable.tableHeader.documentHeader', { - defaultMessage: 'Document', - }), - isSortable: false, - isRemoveable: false, - colLeftIdx: -1, - colRightIdx: -1, - }, - ] - : columns.map((column, idx) => { - const field = dataView.getFieldByName(column); - return { - name: column, - displayName: field?.displayName ?? column, - isSortable: !!(field && field.sortable), - isRemoveable: column !== '_source' || columns.length > 1, - colLeftIdx: idx - 1 < 0 ? -1 : idx - 1, - colRightIdx: idx + 1 >= columns.length ? -1 : idx + 1, - }; - }); - - return !hideTimeField && dataView.timeFieldName - ? [getTimeColumn(dataView.timeFieldName), ...columnProps] - : columnProps; -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/score_sort_warning.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/score_sort_warning.tsx deleted file mode 100644 index 188a92ea98579..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/score_sort_warning.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiIconTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export function DocViewTableScoreSortWarning() { - const tooltipContent = i18n.translate('discover.docViews.table.scoreSortWarningTooltip', { - defaultMessage: 'In order to retrieve values for _score, you must sort by it.', - }); - - return ; -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx deleted file mode 100644 index 7aa3988444388..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx +++ /dev/null @@ -1,223 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { TableHeader } from './table_header'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { DOC_HIDE_TIME_COLUMN_SETTING } from '@kbn/discover-utils'; -import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; - -const defaultUiSettings = { - get: (key: string) => { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return false; - } else if (key === FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE) { - return false; - } - }, -}; - -function getMockDataView() { - return { - id: 'test', - title: 'Test', - timeFieldName: 'time', - fields: [], - isTimeNanosBased: () => false, - getFieldByName: (name: string) => { - if (name === 'test1') { - return { - name, - displayName: name, - type: 'string', - aggregatable: false, - searchable: true, - sortable: true, - } as DataViewField; - } else { - return { - name, - displayName: name, - type: 'string', - aggregatable: false, - searchable: true, - sortable: false, - } as DataViewField; - } - }, - } as unknown as DataView; -} - -function getMockProps(props = {}) { - const defaultProps = { - dataView: getMockDataView(), - hideTimeColumn: false, - columns: ['first', 'middle', 'last'], - defaultSortOrder: 'desc', - sortOrder: [['time', 'asc']] as SortOrder[], - isShortDots: true, - onRemoveColumn: jest.fn(), - onChangeSortOrder: jest.fn(), - onMoveColumn: jest.fn(), - onPageNext: jest.fn(), - onPagePrevious: jest.fn(), - }; - - return Object.assign({}, defaultProps, props); -} - -describe('TableHeader with time column', () => { - const props = getMockProps(); - - const wrapper = mountWithIntl( - - - - - -
-
- ); - - test('renders correctly', () => { - const docTableHeader = findTestSubject(wrapper, 'docTableHeader'); - expect(docTableHeader.getDOMNode()).toMatchSnapshot(); - }); - - test('time column is sortable with button, cycling sort direction', () => { - findTestSubject(wrapper, 'docTableHeaderFieldSort_time').simulate('click'); - expect(props.onChangeSortOrder).toHaveBeenCalledWith([['time', 'desc']]); - }); - - test('time column is not removeable, no button displayed', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-time'); - expect(removeButton.length).toBe(0); - }); - - test('time column is not moveable, no button displayed', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-time'); - expect(moveButtonLeft.length).toBe(0); - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-time'); - expect(moveButtonRight.length).toBe(0); - }); - - test('first column is removeable', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first'); - expect(removeButton.length).toBe(1); - removeButton.simulate('click'); - expect(props.onRemoveColumn).toHaveBeenCalledWith('first'); - }); - - test('first column is not moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first'); - expect(moveButtonLeft.length).toBe(0); - }); - - test('first column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1); - }); - - test('middle column is moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0); - }); - - test('middle column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2); - }); - - test('last column moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1); - }); -}); - -describe('TableHeader without time column', () => { - const props = getMockProps({ hideTimeColumn: true }); - - const wrapper = mountWithIntl( - { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return true; - } - }, - }, - }} - > - - - - -
-
- ); - - test('renders correctly', () => { - const docTableHeader = findTestSubject(wrapper, 'docTableHeader'); - expect(docTableHeader.getDOMNode()).toMatchSnapshot(); - }); - - test('first column is removeable', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first'); - expect(removeButton.length).toBe(1); - removeButton.simulate('click'); - expect(props.onRemoveColumn).toHaveBeenCalledWith('first'); - }); - - test('first column is not moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first'); - expect(moveButtonLeft.length).toBe(0); - }); - - test('first column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1); - }); - - test('middle column is moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0); - }); - - test('middle column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2); - }); - - test('last column moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx deleted file mode 100644 index 04583c893841f..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx +++ /dev/null @@ -1,71 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useMemo } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '@kbn/discover-utils'; -import { TableHeaderColumn } from './table_header_column'; -import { getDisplayedColumns } from './helpers'; -import { getDefaultSort } from '../../../../utils/sorting'; -import { useDiscoverServices } from '../../../../hooks/use_discover_services'; - -interface Props { - columns: string[]; - dataView: DataView; - onChangeSortOrder?: (sortOrder: SortOrder[]) => void; - onMoveColumn?: (name: string, index: number) => void; - onRemoveColumn?: (name: string) => void; - sortOrder: SortOrder[]; -} - -export function TableHeader({ - columns, - dataView, - onChangeSortOrder, - onMoveColumn, - onRemoveColumn, - sortOrder, -}: Props) { - const { uiSettings } = useDiscoverServices(); - const [defaultSortOrder, hideTimeColumn, isShortDots] = useMemo( - () => [ - uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'), - uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false), - uiSettings.get(FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE), - ], - [uiSettings] - ); - const displayedColumns = getDisplayedColumns(columns, dataView, hideTimeColumn, isShortDots); - - return ( - - - {displayedColumns.map((col, index) => { - return ( - - ); - })} - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx deleted file mode 100644 index cbb1cb598f2c5..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx +++ /dev/null @@ -1,234 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiButtonIcon, EuiToolTip, EuiIconTip } from '@elastic/eui'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { DocViewTableScoreSortWarning } from './score_sort_warning'; - -interface Props { - colLeftIdx: number; // idx of the column to the left, -1 if moving is not possible - colRightIdx: number; // idx of the column to the right, -1 if moving is not possible - displayName?: string; - isRemoveable: boolean; - isSortable: boolean; - isTimeColumn: boolean; - customLabel?: string; - name: string; - onChangeSortOrder?: (sortOrder: SortOrder[]) => void; - onMoveColumn?: (name: string, idx: number) => void; - onRemoveColumn?: (name: string) => void; - sortOrder: SortOrder[]; -} - -interface IconProps { - iconType: string; - color: 'primary' | 'text'; -} - -interface IconButtonProps { - active: boolean; - ariaLabel: string; - className: string; - iconProps: IconProps; - onClick: () => void | undefined; - testSubject: string; - tooltip: string; -} - -const sortDirectionToIcon: Record = { - desc: { iconType: 'sortDown', color: 'primary' }, - asc: { iconType: 'sortUp', color: 'primary' }, - '': { iconType: 'sortable', color: 'text' }, -}; - -const ICON_BUTTON_STYLE = { width: 12, height: 12 }; - -export function TableHeaderColumn({ - colLeftIdx, - colRightIdx, - displayName, - isRemoveable, - isSortable, - isTimeColumn, - customLabel, - name, - onChangeSortOrder, - onMoveColumn, - onRemoveColumn, - sortOrder, -}: Props) { - const [, sortDirection = ''] = sortOrder.find((sortPair) => name === sortPair[0]) || []; - const curSortWithoutCol = sortOrder.filter((pair) => pair[0] !== name); - const curColSort = sortOrder.find((pair) => pair[0] === name); - const curColSortDir = (curColSort && curColSort[1]) || ''; - - const fieldName = customLabel ?? displayName; - const timeAriaLabel = i18n.translate( - 'discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel', - { - defaultMessage: '{timeFieldName} - this field represents the time that events occurred.', - values: { timeFieldName: fieldName }, - } - ); - const timeTooltip = i18n.translate('discover.docTable.tableHeader.timeFieldIconTooltip', { - defaultMessage: 'This field represents the time that events occurred.', - }); - - // If this is the _score column, and _score is not one of the columns inside the sort, show a - // warning that the _score will not be retrieved from Elasticsearch - const showScoreSortWarning = name === '_score' && !curColSort; - - const handleChangeSortOrder = () => { - if (!onChangeSortOrder) return; - - // Cycle goes Unsorted -> Asc -> Desc -> Unsorted - if (curColSort === undefined) { - onChangeSortOrder([...curSortWithoutCol, [name, 'asc']]); - } else if (curColSortDir === 'asc') { - onChangeSortOrder([...curSortWithoutCol, [name, 'desc']]); - } else if (curColSortDir === 'desc' && curSortWithoutCol.length === 0) { - // If we're at the end of the cycle and this is the only existing sort, we switch - // back to ascending sort instead of removing it. - onChangeSortOrder([[name, 'asc']]); - } else { - onChangeSortOrder(curSortWithoutCol); - } - }; - - const getSortButtonAriaLabel = () => { - const sortAscendingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnAscendingAriaLabel', - { - defaultMessage: 'Sort {columnName} ascending', - values: { columnName: name }, - } - ); - const sortDescendingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnDescendingAriaLabel', - { - defaultMessage: 'Sort {columnName} descending', - values: { columnName: name }, - } - ); - const stopSortingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnUnsortedAriaLabel', - { - defaultMessage: 'Stop sorting on {columnName}', - values: { columnName: name }, - } - ); - - if (curColSort === undefined) { - return sortAscendingMessage; - } else if (sortDirection === 'asc') { - return sortDescendingMessage; - } else if (sortDirection === 'desc' && curSortWithoutCol.length === 0) { - return sortAscendingMessage; - } else { - return stopSortingMessage; - } - }; - - // action buttons displayed on the right side of the column name - const buttons: IconButtonProps[] = [ - // Sort Button - { - active: isSortable && typeof onChangeSortOrder === 'function', - ariaLabel: getSortButtonAriaLabel(), - className: !sortDirection ? 'kbnDocTableHeader__sortChange' : '', - iconProps: sortDirectionToIcon[sortDirection], - onClick: handleChangeSortOrder, - testSubject: `docTableHeaderFieldSort_${name}`, - tooltip: getSortButtonAriaLabel(), - }, - // Remove Button - { - active: isRemoveable && typeof onRemoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.removeColumnButtonAriaLabel', { - defaultMessage: 'Remove {columnName} column', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'cross', color: 'text' }, - onClick: () => onRemoveColumn && onRemoveColumn(name), - testSubject: `docTableRemoveHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.removeColumnButtonTooltip', { - defaultMessage: 'Remove Column', - }), - }, - // Move Left Button - { - active: colLeftIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonAriaLabel', { - defaultMessage: 'Move {columnName} column to the left', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'sortLeft', color: 'text' }, - onClick: () => onMoveColumn && onMoveColumn(name, colLeftIdx), - testSubject: `docTableMoveLeftHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonTooltip', { - defaultMessage: 'Move column to the left', - }), - }, - // Move Right Button - { - active: colRightIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonAriaLabel', { - defaultMessage: 'Move {columnName} column to the right', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'sortRight', color: 'text' }, - onClick: () => onMoveColumn && onMoveColumn(name, colRightIdx), - testSubject: `docTableMoveRightHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonTooltip', { - defaultMessage: 'Move column to the right', - }), - }, - ]; - - return ( - - - {showScoreSortWarning && } - {fieldName} - {isTimeColumn && ( - - )} - {buttons - .filter((button) => button.active) - .map((button, idx) => ( - - - - ))} - - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx deleted file mode 100644 index 3452da4abc57e..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx +++ /dev/null @@ -1,141 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl, findTestSubject } from '@kbn/test-jest-helpers'; -import { TableRow, TableRowProps } from './table_row'; -import { createFilterManagerMock } from '@kbn/data-plugin/public/query/filter_manager/filter_manager.mock'; -import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { discoverServiceMock } from '../../../__mocks__/services'; - -import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '@kbn/discover-utils'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import type { EsHitRecord } from '@kbn/discover-utils/types'; - -jest.mock('../utils/row_formatter', () => { - const originalModule = jest.requireActual('../utils/row_formatter'); - return { - ...originalModule, - formatRow: () => { - return mocked_document_cell; - }, - }; -}); - -const mountComponent = (props: TableRowProps) => { - return mountWithIntl( - { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return true; - } else if (key === MAX_DOC_FIELDS_DISPLAYED) { - return 100; - } - }, - }, - }} - > - - - - -
-
- ); -}; - -const mockHit = { - _index: 'mock_index', - _id: '1', - _score: 1, - _type: '_doc', - fields: [ - { - timestamp: '2020-20-01T12:12:12.123', - }, - ], - _source: { message: 'mock_message', bytes: 20 }, -} as unknown as EsHitRecord; - -const mockFilterManager = createFilterManagerMock(); - -describe('Doc table row component', () => { - const mockInlineFilter = jest.fn(); - const defaultProps = { - columns: ['_source'], - filter: mockInlineFilter, - dataView: dataViewWithTimefieldMock, - row: buildDataTableRecord(mockHit, dataViewWithTimefieldMock), - useNewFieldsApi: true, - filterManager: mockFilterManager, - addBasePath: (path: string) => path, - } as unknown as TableRowProps; - - it('should render __document__ column', () => { - const component = mountComponent({ ...defaultProps, columns: [] }); - const docTableField = findTestSubject(component, 'docTableField'); - expect(docTableField.first().text()).toBe('mocked_document_cell'); - }); - - it('should render message, _index and bytes fields', () => { - const component = mountComponent({ ...defaultProps, columns: ['message', '_index', 'bytes'] }); - - const fields = findTestSubject(component, 'docTableField'); - expect(fields.first().text()).toBe('mock_message'); - expect(fields.last().text()).toBe('20'); - expect(fields.length).toBe(3); - }); - - it('should apply filter when pressed', () => { - const component = mountComponent({ ...defaultProps, columns: ['bytes'] }); - - const fields = findTestSubject(component, 'docTableField'); - expect(fields.first().text()).toBe('20'); - - const filterInButton = findTestSubject(component, 'docTableCellFilter'); - filterInButton.simulate('click'); - expect(mockInlineFilter).toHaveBeenCalledWith( - dataViewWithTimefieldMock.getFieldByName('bytes'), - 20, - '+' - ); - }); - - describe('details row', () => { - it('should be empty by default', () => { - const component = mountComponent(defaultProps); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); - }); - - it('should expand the detail row when the toggle arrow is clicked', () => { - const component = mountComponent(defaultProps); - const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); - - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); - toggleButton.simulate('click'); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeTruthy(); - }); - - it('should hide the single/surrounding views for ES|QL mode', () => { - const props = { - ...defaultProps, - isEsqlMode: true, - }; - const component = mountComponent(props); - const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); - toggleButton.simulate('click'); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').text()).toBe('Expanded result'); - expect(findTestSubject(component, 'docTableRowAction').length).toBeFalsy(); - }); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.tsx deleted file mode 100644 index 40a3a81499a1d..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row.tsx +++ /dev/null @@ -1,239 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment, useCallback, useMemo, useState } from 'react'; -import classNames from 'classnames'; -import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty, EuiIcon } from '@elastic/eui'; -import { DataView } from '@kbn/data-views-plugin/public'; -import { Filter } from '@kbn/es-query'; -import type { - DataTableRecord, - EsHitRecord, - ShouldShowFieldInTableHandler, -} from '@kbn/discover-utils/types'; -import { formatFieldValue } from '@kbn/discover-utils'; -import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; -import { TableCell } from './table_row/table_cell'; -import { formatRow, formatTopLevelObject } from '../utils/row_formatter'; -import { TableRowDetails } from './table_row_details'; -import { useDiscoverServices } from '../../../hooks/use_discover_services'; - -export type DocTableRow = EsHitRecord & { - isAnchor?: boolean; -}; - -export interface TableRowProps { - columns: string[]; - filter?: DocViewFilterFn; - filters?: Filter[]; - isEsqlMode?: boolean; - savedSearchId?: string; - row: DataTableRecord; - rows: DataTableRecord[]; - dataView: DataView; - useNewFieldsApi: boolean; - shouldShowFieldHandler: ShouldShowFieldInTableHandler; - onAddColumn?: (column: string) => void; - onRemoveColumn?: (column: string) => void; -} - -export const TableRow = ({ - filters, - isEsqlMode, - columns, - filter, - savedSearchId, - row, - rows, - dataView, - useNewFieldsApi, - shouldShowFieldHandler, - onAddColumn, - onRemoveColumn, -}: TableRowProps) => { - const { uiSettings, fieldFormats } = useDiscoverServices(); - const [maxEntries, hideTimeColumn] = useMemo( - () => [ - uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), - uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false), - ], - [uiSettings] - ); - const [open, setOpen] = useState(false); - const docTableRowClassName = classNames('kbnDocTable__row', { - 'kbnDocTable__row--highlight': row.isAnchor, - }); - const anchorDocTableRowSubj = row.isAnchor ? ' docTableAnchorRow' : ''; - - const mapping = useMemo(() => dataView.fields.getByName, [dataView]); - - // toggle display of the rows details, a full list of the fields from each row - const toggleRow = () => setOpen((prevOpen) => !prevOpen); - - /** - * Fill an element with the value of a field - */ - const displayField = (fieldName: string) => { - // If we're formatting the _source column, don't use the regular field formatter, - // but our Discover mechanism to format a hit in a better human-readable way. - if (fieldName === '_source') { - return formatRow(row, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - } - - const formattedField = formatFieldValue( - row.flattened[fieldName], - row.raw, - fieldFormats, - dataView, - mapping(fieldName) - ); - - return ( - // formatFieldValue always returns sanitized HTML - // eslint-disable-next-line react/no-danger -
- ); - }; - const inlineFilter = useCallback( - (column: string, type: '+' | '-') => { - const field = dataView.fields.getByName(column); - filter?.(field!, row.flattened[column], type); - }, - [filter, dataView.fields, row.flattened] - ); - - const rowCells = [ - - - {open ? ( - - ) : ( - - )} - - , - ]; - - if (dataView.timeFieldName && !hideTimeColumn) { - rowCells.push( - - ); - } - - if (columns.length === 0 && useNewFieldsApi) { - const formatted = formatRow(row, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - - rowCells.push( - - ); - } else { - columns.forEach(function (column: string, index) { - const cellKey = `${column}-${index}`; - if (useNewFieldsApi && !mapping(column) && row.raw.fields && !row.raw.fields[column]) { - const innerColumns = Object.fromEntries( - Object.entries(row.raw.fields).filter(([key]) => { - return key.indexOf(`${column}.`) === 0; - }) - ); - - rowCells.push( - - ); - } else { - // Check whether the field is defined as filterable in the mapping and does - // NOT have ignored values in it to determine whether we want to allow filtering. - // We should improve this and show a helpful tooltip why the filter buttons are not - // there/disabled when there are ignored values. - const isFilterable = Boolean( - mapping(column)?.filterable && - typeof filter === 'function' && - !row.raw._ignored?.includes(column) - ); - rowCells.push( - - ); - } - }); - } - - return ( - - - {rowCells} - - - {open && ( - - - - )} - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap b/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap deleted file mode 100644 index b4f03267ec810..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap +++ /dev/null @@ -1,369 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Doc table cell component renders a cell with filter buttons if it is filterable 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={true} -> - - - formatted content - - - - - - - - - - , - "ctr": 2, - "insertionPoint": undefined, - "isSpeedy": false, - "key": "css", - "nonce": undefined, - "prepend": undefined, - "tags": Array [ - , - , - ], - }, - } - } - isStringTag={true} - serialized={ - Object { - "map": undefined, - "name": "jcaat8-euiToolTipAnchor-inlineBlock", - "next": undefined, - "styles": "*[disabled]{pointer-events:none;};label:euiToolTipAnchor;;;display:inline-block;label:inlineBlock;;;", - "toString": [Function], - } - } - /> - - - - - - - - - - - - - , - "ctr": 2, - "insertionPoint": undefined, - "isSpeedy": false, - "key": "css", - "nonce": undefined, - "prepend": undefined, - "tags": Array [ - , - , - ], - }, - } - } - isStringTag={true} - serialized={ - Object { - "map": undefined, - "name": "jcaat8-euiToolTipAnchor-inlineBlock", - "next": undefined, - "styles": "*[disabled]{pointer-events:none;};label:euiToolTipAnchor;;;display:inline-block;label:inlineBlock;;;", - "toString": [Function], - } - } - /> - - - - - - - - - - -`; - -exports[`Doc table cell component renders a cell without filter buttons if it is not filterable 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={true} -> - - - formatted content - - - - -`; - -exports[`Doc table cell component renders a field that is neither a timefield or sourcefield 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={false} -> - - - formatted content - - - - -`; - -exports[`Doc table cell component renders a sourcefield 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={true} - timefield={false} -> - - - formatted content - - - - -`; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss deleted file mode 100644 index 2e643c195208c..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss +++ /dev/null @@ -1,47 +0,0 @@ -.kbnDocTableCell__dataField { - white-space: pre-wrap; -} - -.kbnDocTableCell__toggleDetails { - padding: $euiSizeXS 0 0 0 !important; -} - -/** - * Fixes time column width in Firefox after toggle display of the rows details. - * Described issue - https://github.com/elastic/kibana/pull/104361#issuecomment-894271241 - */ -.kbnDocTableCell--extraWidth { - width: 1%; -} - -.kbnDocTableCell__filter { - position: absolute; - white-space: nowrap; - right: 0; -} - -.kbnDocTableCell__filterButton { - font-size: $euiFontSizeXS; - padding: $euiSizeXS; -} - -/** - * 1. Align icon with text in cell. - * 2. Use opacity to make this element accessible to screen readers and keyboard. - * 3. Show on focus to enable keyboard accessibility. - */ - -.kbnDocTableRowFilterButton { - appearance: none; - background-color: $euiColorEmptyShade; - border: none; - padding: 0 $euiSizeXS; - font-size: $euiFontSizeS; - line-height: 1; /* 1 */ - display: inline-block; - opacity: 0; /* 2 */ - - &:focus { - opacity: 1; /* 3 */ - } -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss deleted file mode 100644 index cc6ccfe9fd29f..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 1. Visually align the actions with the tabs. We can improve this by using flexbox instead, at a later point. - */ -.kbnDocTableDetails__actions { - float: right; - padding-top: $euiSizeS; /* 1 */ -} - -// Overwrite the border on the bootstrap table -.kbnDocTableDetails__row { - - > td { - // Offsets negative margins from an inner flex group - padding: $euiSizeL !important; - - tr:hover td { - background: tintOrShade($euiColorLightestShade, 50%, 20%); - } - } - - td { - border-top: none !important; - } -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss deleted file mode 100644 index c7ccdaa39ff65..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'cell'; -@import 'details'; -@import 'open'; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss deleted file mode 100644 index 659481e0968b5..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 1. When switching between open and closed, the toggle changes size - * slightly which is a problem because it forces the entire table to - * re-render which is SLOW. - */ - -.kbnDocTableOpen__button { - appearance: none; - background-color: transparent; - padding: 0; - border: none; - width: 14px; /* 1 */ - height: 14px; -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx deleted file mode 100644 index ed8d05d87949a..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { CellProps, TableCell } from './table_cell'; - -const mountComponent = (props: Omit) => { - return mount( {}} />); -}; - -describe('Doc table cell component', () => { - test('renders a cell without filter buttons if it is not filterable', () => { - const component = mountComponent({ - filterable: false, - column: 'foo', - timefield: true, - sourcefield: false, - formatted: formatted content, - }); - expect(component).toMatchSnapshot(); - }); - - it('renders a cell with filter buttons if it is filterable', () => { - expect( - mountComponent({ - filterable: true, - column: 'foo', - timefield: true, - sourcefield: false, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); - - it('renders a sourcefield', () => { - expect( - mountComponent({ - filterable: false, - column: 'foo', - timefield: false, - sourcefield: true, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); - - it('renders a field that is neither a timefield or sourcefield', () => { - expect( - mountComponent({ - filterable: false, - column: 'foo', - timefield: false, - sourcefield: false, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx deleted file mode 100644 index 83f60dd50587c..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx +++ /dev/null @@ -1,43 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import classNames from 'classnames'; -import { TableCellActions } from './table_cell_actions'; -export interface CellProps { - timefield: boolean; - sourcefield?: boolean; - formatted: JSX.Element; - filterable: boolean; - column: string; - inlineFilter: (column: string, type: '+' | '-') => void; -} - -export const TableCell = (props: CellProps) => { - const classes = classNames({ - ['eui-textNoWrap kbnDocTableCell--extraWidth']: props.timefield, - ['eui-textBreakAll eui-textBreakWord']: props.sourcefield, - ['kbnDocTableCell__dataField eui-textBreakAll eui-textBreakWord']: - !props.timefield && !props.sourcefield, - }); - - const handleFilterFor = () => props.inlineFilter(props.column, '+'); - const handleFilterOut = () => props.inlineFilter(props.column, '-'); - - return ( - - {props.formatted} - {props.filterable ? ( - - ) : ( - - )} - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx deleted file mode 100644 index cc096bd1cafd5..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiIcon, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -interface TableCellActionsProps { - handleFilterFor: () => void; - handleFilterOut: () => void; -} - -export const TableCellActions = ({ handleFilterFor, handleFilterOut }: TableCellActionsProps) => { - return ( - - - - - - - - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx b/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx deleted file mode 100644 index eefb0f638935f..0000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx +++ /dev/null @@ -1,127 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiButtonEmpty, EuiTitle } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { Filter } from '@kbn/es-query'; -import { useNavigationProps } from '../../../hooks/use_navigation_props'; - -interface TableRowDetailsProps { - children: JSX.Element; - colLength: number; - rowIndex: string | undefined; - rowId: string | undefined; - columns: string[]; - isTimeBased: boolean; - dataView: DataView; - filters?: Filter[]; - savedSearchId?: string; - isEsqlMode?: boolean; -} - -export const TableRowDetails = ({ - colLength, - isTimeBased, - children, - dataView, - rowIndex, - rowId, - columns, - filters, - savedSearchId, - isEsqlMode, -}: TableRowDetailsProps) => { - const { singleDocHref, contextViewHref, onOpenSingleDoc, onOpenContextView } = useNavigationProps( - { - dataView, - rowIndex, - rowId, - columns, - filters, - savedSearchId, - } - ); - - return ( - - - - - - - - - -

- {isEsqlMode && ( - - )} - {!isEsqlMode && ( - - )} -

-
-
-
-
- {!isEsqlMode && ( - - - - {isTimeBased && ( - /* eslint-disable-next-line @elastic/eui/href-or-on-click */ - - - - )} - - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - - - - - - - )} -
-
{children}
- - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx b/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx deleted file mode 100644 index 9d12c2fba3377..0000000000000 --- a/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { DocTableEmbeddable, DocTableEmbeddableProps } from './doc_table_embeddable'; - -export function DiscoverDocTableEmbeddable(renderProps: DocTableEmbeddableProps) { - return ( - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/doc_table_context.tsx b/src/plugins/discover/public/components/doc_table/doc_table_context.tsx deleted file mode 100644 index c1e685d1d8048..0000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_context.tsx +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment } from 'react'; -import './index.scss'; -import { SkipBottomButton } from '../../application/main/components/skip_bottom_button'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; - -const DocTableWrapperMemoized = React.memo(DocTableWrapper); - -const renderDocTable = (tableProps: DocTableRenderProps) => { - return ( - - - - {tableProps.renderHeader()} - {tableProps.renderRows(tableProps.rows)} -
- - ​ - -
- ); -}; - -export const DocTableContext = (props: DocTableProps) => { - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx b/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx deleted file mode 100644 index 1c1274a739f1c..0000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx +++ /dev/null @@ -1,141 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo, useCallback, useMemo, useRef } from 'react'; -import './index.scss'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiText } from '@elastic/eui'; -import { usePager } from '@kbn/discover-utils'; -import type { SearchResponseWarning } from '@kbn/search-response-warnings'; -import { - ToolBarPagination, - MAX_ROWS_PER_PAGE_OPTION, -} from './components/pager/tool_bar_pagination'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; -import { SavedSearchEmbeddableBase } from '../../embeddable/components/saved_search_embeddable_base'; - -export interface DocTableEmbeddableProps extends Omit { - totalHitCount?: number; - rowsPerPageState?: number; - sampleSizeState: number; - interceptedWarnings?: SearchResponseWarning[]; - onUpdateRowsPerPage?: (rowsPerPage?: number) => void; -} - -export type DocTableEmbeddableSearchProps = Omit< - DocTableEmbeddableProps, - 'sampleSizeState' | 'isEsqlMode' ->; - -const DocTableWrapperMemoized = memo(DocTableWrapper); - -export const DocTableEmbeddable = (props: DocTableEmbeddableProps) => { - const onUpdateRowsPerPage = props.onUpdateRowsPerPage; - const tableWrapperRef = useRef(null); - const { - curPageIndex, - pageSize, - totalPages, - startIndex, - hasNextPage, - changePageIndex, - changePageSize, - } = usePager({ - initialPageSize: - typeof props.rowsPerPageState === 'number' && props.rowsPerPageState > 0 - ? Math.min(props.rowsPerPageState, MAX_ROWS_PER_PAGE_OPTION) - : 50, - totalItems: props.rows.length, - }); - const showPagination = totalPages !== 0; - - const scrollTop = useCallback(() => { - if (tableWrapperRef.current) { - tableWrapperRef.current.scrollTo(0, 0); - } - }, []); - - const pageOfItems = useMemo( - () => props.rows.slice(startIndex, pageSize + startIndex), - [pageSize, startIndex, props.rows] - ); - - const onPageChange = useCallback( - (page: number) => { - scrollTop(); - changePageIndex(page); - }, - [changePageIndex, scrollTop] - ); - - const onPageSizeChange = useCallback( - (size: number) => { - scrollTop(); - changePageSize(size); - onUpdateRowsPerPage?.(size); // to update `rowsPerPage` input param for the embeddable - }, - [changePageSize, scrollTop, onUpdateRowsPerPage] - ); - - const shouldShowLimitedResultsWarning = useMemo( - () => !hasNextPage && props.totalHitCount && props.rows.length < props.totalHitCount, - [hasNextPage, props.rows.length, props.totalHitCount] - ); - - const renderDocTable = useCallback( - (renderProps: DocTableRenderProps) => { - return ( -
- - {renderProps.renderHeader()} - {renderProps.renderRows(pageOfItems)} -
-
- ); - }, - [pageOfItems] - ); - - return ( - - - - ) : undefined - } - append={ - showPagination ? ( - - ) : undefined - } - > - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx b/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx deleted file mode 100644 index 5a667ea6f70d4..0000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment, memo, useCallback, useEffect, useRef, useState } from 'react'; -import './index.scss'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { debounce } from 'lodash'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; -import { SkipBottomButton } from '../../application/main/components/skip_bottom_button'; -import { shouldLoadNextDocPatch } from './utils/should_load_next_doc_patch'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; -import { getAllowedSampleSize } from '../../utils/get_allowed_sample_size'; -import { useAppStateSelector } from '../../application/main/state_management/discover_app_state_container'; - -const FOOTER_PADDING = { padding: 0 }; - -const DocTableWrapperMemoized = memo(DocTableWrapper); - -interface DocTableInfiniteContentProps extends DocTableRenderProps { - limit: number; - onSetMaxLimit: () => void; - onBackToTop: () => void; -} - -const DocTableInfiniteContent = ({ - rows, - columnLength, - limit, - onSkipBottomButtonClick, - renderHeader, - renderRows, - onSetMaxLimit, - onBackToTop, -}: DocTableInfiniteContentProps) => { - const { uiSettings } = useDiscoverServices(); - const sampleSize = useAppStateSelector((state) => - getAllowedSampleSize(state.sampleSize, uiSettings) - ); - - const onSkipBottomButton = useCallback(() => { - onSetMaxLimit(); - onSkipBottomButtonClick(); - }, [onSetMaxLimit, onSkipBottomButtonClick]); - - return ( - - - - {renderHeader()} - {renderRows(rows.slice(0, limit))} - - - - - -
- {rows.length === sampleSize ? ( -
- - - - -
- ) : ( - - ​ - - )} -
-
- ); -}; - -export const DocTableInfinite = (props: DocTableProps) => { - const tableWrapperRef = useRef(null); - const [limit, setLimit] = useState(50); - - /** - * depending on which version of Discover is displayed, different elements are scrolling - * and have therefore to be considered for calculation of infinite scrolling - */ - useEffect(() => { - // After mounting table wrapper should be initialized - const scrollDiv = tableWrapperRef.current as HTMLDivElement; - const scrollMobileElem = document.documentElement; - - const scheduleCheck = debounce(() => { - const isMobileView = document.getElementsByClassName('dscSidebar__mobile').length > 0; - - const usedScrollDiv = isMobileView ? scrollMobileElem : scrollDiv; - if (shouldLoadNextDocPatch(usedScrollDiv)) { - setLimit((prevLimit) => prevLimit + 50); - } - }, 50); - - scrollDiv.addEventListener('scroll', scheduleCheck); - window.addEventListener('scroll', scheduleCheck); - - scheduleCheck(); - - return () => { - scrollDiv.removeEventListener('scroll', scheduleCheck); - window.removeEventListener('scroll', scheduleCheck); - }; - }, []); - - const onBackToTop = useCallback(() => { - const isMobileView = document.getElementsByClassName('dscSidebar__mobile').length > 0; - const focusElem = document.querySelector('.dscSkipButton') as HTMLElement; - focusElem.focus(); - - // Only the desktop one needs to target a specific container - if (!isMobileView && tableWrapperRef.current) { - tableWrapperRef.current.scrollTo(0, 0); - } else if (window) { - window.scrollTo(0, 0); - } - }, []); - - const setMaxLimit = useCallback(() => setLimit(props.rows.length), [props.rows.length]); - - const renderDocTable = useCallback( - (tableProps: DocTableRenderProps) => ( - - ), - [limit, onBackToTop, setMaxLimit] - ); - - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx deleted file mode 100644 index fbbe460320cdb..0000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx +++ /dev/null @@ -1,81 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; -import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; -import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { DocTableWrapper, DocTableWrapperProps } from './doc_table_wrapper'; -import { discoverServiceMock } from '../../__mocks__/services'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import type { EsHitRecord } from '@kbn/discover-utils/types'; - -describe('Doc table component', () => { - const mountComponent = (customProps?: Partial) => { - const props = { - columns: ['_source'], - dataView: dataViewMock, - rows: [ - { - _index: 'mock_index', - _id: '1', - _score: 1, - fields: [ - { - timestamp: '2020-20-01T12:12:12.123', - }, - ], - _source: { message: 'mock_message', bytes: 20 }, - } as EsHitRecord, - ].map((row) => buildDataTableRecord(row, dataViewMock)), - sort: [['order_date', 'desc']], - isLoading: false, - searchDescription: '', - onAddColumn: () => {}, - onFilter: () => {}, - onMoveColumn: () => {}, - onRemoveColumn: () => {}, - onSort: () => {}, - useNewFieldsApi: true, - dataTestSubj: 'discoverDocTable', - render: () => { - return
mock
; - }, - ...(customProps || {}), - }; - - return mountWithIntl( - - - - ); - }; - - it('should render infinite table correctly', () => { - const component = mountComponent(); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeTruthy(); - expect(component.find('.kbnDocTable__error').exists()).toBeFalsy(); - }); - - it('should render error fallback if rows array is empty', () => { - const component = mountComponent({ rows: [], isLoading: false }); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeFalsy(); - expect(component.find('.kbnDocTable__error').find(EuiIcon).exists()).toBeTruthy(); - }); - - it('should render loading indicator', () => { - const component = mountComponent({ rows: [], isLoading: true }); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeFalsy(); - expect(component.find('.kbnDocTable__error').find(EuiLoadingSpinner).exists()).toBeTruthy(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx deleted file mode 100644 index b9fb8b6681e20..0000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx +++ /dev/null @@ -1,253 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { forwardRef, useCallback, useMemo } from 'react'; -import { EuiIcon, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui'; -import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { Filter } from '@kbn/es-query'; -import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { SHOW_MULTIFIELDS, getShouldShowFieldHandler } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { TableHeader } from './components/table_header/table_header'; -import { TableRow } from './components/table_row'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; - -export interface DocTableProps { - /** - * Rows of classic table - */ - rows: DataTableRecord[]; - /** - * Columns of classic table - */ - columns: string[]; - /** - * Current DataView - */ - dataView: DataView; - /** - * Current sorting - */ - sort: string[][]; - /** - * New fields api switch - */ - useNewFieldsApi: boolean; - /** - * Current search description - */ - searchDescription?: string; - /** - * Current shared item title - */ - sharedItemTitle?: string; - /** - * Current data test subject - */ - dataTestSubj: string; - /** - * Loading state - */ - isLoading: boolean; - /** - * Filters applied by embeddalbe - */ - filters?: Filter[]; - /** - * Flag which identifies if Discover operates - * in ES|QL mode - */ - isEsqlMode?: boolean; - /** - * Saved search id - */ - savedSearchId?: string; - /** - * Filter callback - */ - onFilter?: DocViewFilterFn; - /** - * Sorting callback - */ - onSort?: (sort: string[][]) => void; - /** - * Add columns callback - */ - onAddColumn?: (column: string) => void; - /** - * Reordering column callback - */ - onMoveColumn?: (columns: string, newIdx: number) => void; - /** - * Remove column callback - */ - onRemoveColumn?: (column: string) => void; -} - -export interface DocTableRenderProps { - columnLength: number; - rows: DataTableRecord[]; - renderRows: (row: DataTableRecord[]) => JSX.Element[]; - renderHeader: () => JSX.Element; - onSkipBottomButtonClick: () => void; -} - -export interface DocTableWrapperProps extends DocTableProps { - /** - * Renders Doc table content - */ - render: (params: DocTableRenderProps) => JSX.Element; -} - -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export const DocTableWrapper = forwardRef( - ( - { - render, - columns, - filters, - isEsqlMode, - savedSearchId, - rows, - dataView, - onSort, - onAddColumn, - onMoveColumn, - onRemoveColumn, - sort, - onFilter, - useNewFieldsApi, - searchDescription, - sharedItemTitle, - dataTestSubj, - isLoading, - }: DocTableWrapperProps, - ref - ) => { - const { uiSettings } = useDiscoverServices(); - const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS, false), [uiSettings]); - - const onSkipBottomButtonClick = useCallback(async () => { - // delay scrolling to after the rows have been rendered - const bottomMarker = document.getElementById('discoverBottomMarker'); - - while (rows.length !== document.getElementsByClassName('kbnDocTable__row').length) { - await wait(50); - } - bottomMarker!.focus(); - await wait(50); - bottomMarker!.blur(); - }, [rows]); - - const shouldShowFieldHandler = useMemo( - () => - getShouldShowFieldHandler( - dataView.fields.map((field: DataViewField) => field.name), - dataView, - showMultiFields - ), - [dataView, showMultiFields] - ); - - const renderHeader = useCallback( - () => ( - - ), - [columns, dataView, onMoveColumn, onRemoveColumn, onSort, sort] - ); - - const renderRows = useCallback( - (rowsToRender: DataTableRecord[]) => { - return rowsToRender.map((current) => ( - - )); - }, - [ - columns, - filters, - savedSearchId, - onFilter, - dataView, - useNewFieldsApi, - shouldShowFieldHandler, - onAddColumn, - onRemoveColumn, - isEsqlMode, - rows, - ] - ); - - return ( -
} - > - {rows.length !== 0 && - render({ - columnLength: columns.length, - rows, - onSkipBottomButtonClick, - renderHeader, - renderRows, - })} - {!rows.length && ( -
- - {isLoading ? ( - <> - - - - - ) : ( - <> - - - - - )} - -
- )} -
- ); - } -); diff --git a/src/plugins/discover/public/components/doc_table/index.scss b/src/plugins/discover/public/components/doc_table/index.scss deleted file mode 100644 index 3663d807851c4..0000000000000 --- a/src/plugins/discover/public/components/doc_table/index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'doc_table'; -@import 'components/index'; diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss b/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss deleted file mode 100644 index ede39feed30b6..0000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss +++ /dev/null @@ -1,7 +0,0 @@ -// Special handling for images coming from the image field formatter -// See discover_grid.scss for more explanation on those values -.rowFormatter__value img { - vertical-align: middle; - max-height: lineHeightFromBaseline(2) !important; - max-width: ($euiSizeXXL * 12.5) !important; -} diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts b/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts deleted file mode 100644 index d7cb720b78814..0000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts +++ /dev/null @@ -1,313 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ReactDOM from 'react-dom/server'; -import { formatRow, formatTopLevelObject } from './row_formatter'; -import { DataView } from '@kbn/data-views-plugin/public'; -import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; -import { DiscoverServices } from '../../../build_services'; -import { stubbedSavedObjectIndexPattern } from '@kbn/data-plugin/common/stubs'; -import { buildDataTableRecord } from '@kbn/discover-utils'; - -describe('Row formatter', () => { - let services: DiscoverServices; - - const createIndexPattern = () => { - const id = 'my-index'; - const { - type, - version, - attributes: { timeFieldName, fields, title }, - } = stubbedSavedObjectIndexPattern(id); - - return new DataView({ - spec: { id, type, version, timeFieldName, fields: JSON.parse(fields), title }, - fieldFormats: fieldFormatsMock, - shortDotsEnable: false, - metaFields: ['_id', '_type', '_score'], - }); - }; - - const dataView = createIndexPattern(); - const rawHit = { - _id: 'a', - _index: 'foo', - _score: 1, - _source: { - foo: 'bar', - number: 42, - hello: '

World

', - also: 'with "quotes" or \'single quotes\'', - }, - }; - const hit = buildDataTableRecord(rawHit, dataView); - - const shouldShowField = (fieldName: string) => - dataView.fields.getAll().some((fld) => fld.name === fieldName); - - beforeEach(() => { - services = { - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, - } as unknown as DiscoverServices; - }); - - it('formats document properly', () => { - expect(formatRow(hit, dataView, shouldShowField, 100, services.fieldFormats)) - .toMatchInlineSnapshot(` - World", - "hello", - ], - Array [ - "number", - 42, - "number", - ], - Array [ - "_id", - "a", - "_id", - ], - Array [ - "_score", - 1, - "_score", - ], - ] - } - /> - `); - }); - - it('limits number of rendered items', () => { - services = { - uiSettings: { - get: () => 1, - }, - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, - } as unknown as DiscoverServices; - expect(formatRow(hit, dataView, () => false, 1, services.fieldFormats)).toMatchInlineSnapshot(` - - `); - }); - - it('formats document with highlighted fields first', () => { - const highLightHit = buildDataTableRecord( - { ...rawHit, highlight: { number: ['42'] } }, - dataView - ); - - expect(formatRow(highLightHit, dataView, shouldShowField, 100, services.fieldFormats)) - .toMatchInlineSnapshot(` - World", - "hello", - ], - Array [ - "_id", - "a", - "_id", - ], - Array [ - "_score", - 1, - "_score", - ], - ] - } - /> - `); - }); - - it('formats top level objects using formatter', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - }, - }, - { - 'object.value': [5, 10], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); - - it('formats top level objects in alphabetical order', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - const formatted = ReactDOM.renderToStaticMarkup( - formatTopLevelObject( - { fields: { 'a.zzz': [100], 'a.ccc': [50] } }, - { 'a.zzz': [100], 'a.ccc': [50], getByName: jest.fn() }, - dataView, - 100 - ) - ); - expect(formatted.indexOf('
a.ccc:
')).toBeLessThan(formatted.indexOf('
a.zzz:
')); - }); - - it('formats top level objects with subfields and highlights', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - 'object.keys': ['a', 'b'], - }, - highlight: { - 'object.keys': 'a', - }, - }, - { - 'object.value': [5, 10], - 'object.keys': ['a', 'b'], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); - - it('formats top level objects, converting unknown fields to string', () => { - dataView.getFieldByName = jest.fn(); - dataView.getFormatterForField = jest.fn(); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - }, - }, - { - 'object.value': [5, 10], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx b/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx deleted file mode 100644 index ec33f5c16be09..0000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx +++ /dev/null @@ -1,87 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { - DataTableRecord, - ShouldShowFieldInTableHandler, - FormattedHit, -} from '@kbn/discover-utils/types'; -import { formatHit } from '@kbn/discover-utils'; - -import './row_formatter.scss'; - -interface Props { - defPairs: FormattedHit; -} -const TemplateComponent = ({ defPairs }: Props) => { - return ( -
- {defPairs.map((pair, idx) => ( - -
- {pair[0]} - {!!pair[1] && ':'} -
-
{' '} - - ))} -
- ); -}; - -export const formatRow = ( - hit: DataTableRecord, - dataView: DataView, - shouldShowFieldHandler: ShouldShowFieldInTableHandler, - maxEntries: number, - fieldFormats: FieldFormatsStart -) => { - const pairs = formatHit(hit, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - return ; -}; - -export const formatTopLevelObject = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - row: Record, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - fields: Record, - dataView: DataView, - maxEntries: number -) => { - const highlights = row.highlight ?? {}; - const highlightPairs: FormattedHit = []; - const sourcePairs: FormattedHit = []; - const sorted = Object.entries(fields).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)); - sorted.forEach(([key, values]) => { - const field = dataView.getFieldByName(key); - const displayKey = fields.getByName ? fields.getByName(key)?.displayName : undefined; - const formatter = field - ? dataView.getFormatterForField(field) - : { convert: (v: unknown, ..._: unknown[]) => String(v) }; - if (!values.map) return; - const formatted = values - .map((val: unknown) => - formatter.convert(val, 'html', { - field, - hit: row, - }) - ) - .join(', '); - const pairs = highlights[key] ? highlightPairs : sourcePairs; - pairs.push([displayKey ? displayKey : key, formatted, key]); - }); - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts b/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts deleted file mode 100644 index 25d5ef59c5f4e..0000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { shouldLoadNextDocPatch } from './should_load_next_doc_patch'; - -describe('shouldLoadNextDocPatch', () => { - test('next patch should not be loaded', () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 100, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeFalsy(); - }); - - test('next patch should be loaded', () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 350, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeTruthy(); - }); - - test("next patch should be loaded even there's a decimal scroll height", () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 350.34234234, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeTruthy(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts b/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts deleted file mode 100644 index cfb4f93a2adb5..0000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts +++ /dev/null @@ -1,27 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// use a buffer to start rendering more documents before the user completely scrolles down -const verticalScrollBuffer = 100; - -/** - * Helper function to determine if the next patch of 50 documents should be loaded - */ -export function shouldLoadNextDocPatch(domEl: HTMLElement) { - // the height of the scrolling div, including content not visible on the screen due to overflow. - const scrollHeight = domEl.scrollHeight; - // the number of pixels that the div is is scrolled vertically - const scrollTop = domEl.scrollTop; - // the inner height of the scrolling div, excluding content that's visible on the screen - const clientHeight = domEl.clientHeight; - - const consumedHeight = scrollTop + clientHeight; - const remainingHeight = scrollHeight - consumedHeight; - return remainingHeight < verticalScrollBuffer; -} diff --git a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx index 43960f98ea2b8..5b77a184d9253 100644 --- a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx +++ b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx @@ -11,7 +11,7 @@ import React, { useMemo, useEffect, useState, type ReactElement, useCallback } f import { EuiFlexGroup, EuiFlexItem, EuiTab, EuiTabs, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import { isLegacyTableEnabled, SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; +import { SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; import type { DataView } from '@kbn/data-views-plugin/common'; import useMountedState from 'react-use/lib/useMountedState'; import { VIEW_MODE } from '../../../common/constants'; @@ -42,10 +42,6 @@ export const DocumentViewModeToggle = ({ dataVisualizer: dataVisualizerService, aiops: aiopsService, } = useDiscoverServices(); - const isLegacy = useMemo( - () => isLegacyTableEnabled({ uiSettings, isEsqlMode }), - [uiSettings, isEsqlMode] - ); const [showPatternAnalysisTab, setShowPatternAnalysisTab] = useState(null); const showFieldStatisticsTab = useMemo( @@ -93,7 +89,7 @@ export const DocumentViewModeToggle = ({ } }, [showPatternAnalysisTab, viewMode, setDiscoverViewMode]); - const includesNormalTabsStyle = viewMode === VIEW_MODE.AGGREGATED_LEVEL || isLegacy; + const includesNormalTabsStyle = viewMode === VIEW_MODE.AGGREGATED_LEVEL; const containerPadding = includesNormalTabsStyle ? euiTheme.size.s : 0; const containerCss = css` diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.tsx b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx index 153d401cc980a..ab179a87778a3 100644 --- a/src/plugins/discover/public/context_awareness/__mocks__/index.tsx +++ b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx @@ -25,6 +25,7 @@ import { ProfileProviderServices } from '../profile_providers/profile_provider_s import { ProfilesManager } from '../profiles_manager'; import { DiscoverEBTManager } from '../../services/discover_ebt_manager'; import { createLogsContextServiceMock } from '@kbn/discover-utils/src/__mocks__'; +import { discoverSharedPluginMock } from '@kbn/discover-shared-plugin/public/mocks'; export const createContextAwarenessMocks = ({ shouldRegisterProviders = true, @@ -84,6 +85,7 @@ export const createContextAwarenessMocks = ({ }, ], rowHeight: 3, + breakdownField: 'extension', })), getAdditionalCellActions: jest.fn((prev) => () => [ ...prev(), @@ -180,5 +182,6 @@ export const createContextAwarenessMocks = ({ const createProfileProviderServicesMock = () => { return { logsContextService: createLogsContextServiceMock(), + discoverShared: discoverSharedPluginMock.createStartContract(), } as ProfileProviderServices; }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx index 46ecce387e877..07c836b127843 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx @@ -220,6 +220,7 @@ export const createExampleDataSourceProfileProvider = (): DataSourceProfileProvi ]; }, getDefaultAppState: () => () => ({ + breakdownField: 'log.level', columns: [ { name: '@timestamp', diff --git a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts index d9c08af91f5d8..11d5aab2763cd 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { LOG_LEVEL_FIELD } from '@kbn/discover-utils'; import type { DataSourceProfileProvider } from '../../../../profiles'; import { DefaultAppStateColumn } from '../../../../types'; @@ -14,10 +15,12 @@ export const createGetDefaultAppState = ({ defaultColumns, }: { defaultColumns?: DefaultAppStateColumn[]; -}): DataSourceProfileProvider['profile']['getDefaultAppState'] => { +} = {}): DataSourceProfileProvider['profile']['getDefaultAppState'] => { return (prev) => (params) => { const appState = { ...prev(params) }; + appState.breakdownField = LOG_LEVEL_FIELD; + if (defaultColumns) { appState.columns = []; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts index bebd340acfb38..7601680d6155c 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts @@ -13,6 +13,7 @@ import { getCellRenderers, getRowIndicatorProvider, getRowAdditionalLeadingControls, + createGetDefaultAppState, } from './accessors'; import { extractIndexPatternFrom } from '../../extract_index_pattern_from'; import { OBSERVABILITY_ROOT_PROFILE_ID } from '../consts'; @@ -22,6 +23,7 @@ export const createLogsDataSourceProfileProvider = ( ): DataSourceProfileProvider => ({ profileId: 'observability-logs-data-source-profile', profile: { + getDefaultAppState: createGetDefaultAppState(), getCellRenderers, getRowIndicatorProvider, getRowAdditionalLeadingControls, diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.ts b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.ts new file mode 100644 index 0000000000000..42382f088b7a3 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { SecuritySolutionAppWrapperFeature } from '@kbn/discover-shared-plugin/public'; + +export const createAppWrapperAccessor = async ( + appWrapperFeature?: SecuritySolutionAppWrapperFeature +) => { + if (!appWrapperFeature) return undefined; + return appWrapperFeature.getWrapper(); +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx new file mode 100644 index 0000000000000..9774bafdb69b3 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import type { SecuritySolutionCellRendererFeature } from '@kbn/discover-shared-plugin/public'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import { createCellRendererAccessor } from './get_cell_renderer_accessor'; +import { render } from '@testing-library/react'; + +const cellRendererFeature: SecuritySolutionCellRendererFeature = { + id: 'security-solution-cell-renderer', + getRenderer: async () => (fieldName: string) => { + if (fieldName === 'host.name') { + return (props: DataGridCellValueElementProps) => { + return
{props.columnId}
; + }; + } + }, +}; + +const mockCellProps = { + columnId: 'host.name', + row: { + id: '1', + raw: {}, + flattened: {}, + }, +} as DataGridCellValueElementProps; + +describe('getCellRendererAccessort', () => { + it('should return a cell renderer', async () => { + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); + expect(getCellRenderer).toBeDefined(); + const CellRenderer = getCellRenderer?.('host.name') as React.FC; + expect(CellRenderer).toBeDefined(); + const { getByTestId } = render(); + expect(getByTestId('cell-render-feature')).toBeVisible(); + expect(getByTestId('cell-render-feature')).toHaveTextContent('host.name'); + }); + + it('should return undefined if cellRendererFeature is not defined', async () => { + const getCellRenderer = await createCellRendererAccessor(); + expect(getCellRenderer).toBeUndefined(); + }); + + it('should return undefined if cellRendererGetter returns undefined', async () => { + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); + const cellRenderer = getCellRenderer?.('user.name'); + expect(cellRenderer).toBeUndefined(); + }); +}); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx new file mode 100644 index 0000000000000..9f1d18d4a4d90 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx @@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import type { SecuritySolutionCellRendererFeature } from '@kbn/discover-shared-plugin/public'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; + +export const createCellRendererAccessor = async ( + cellRendererFeature?: SecuritySolutionCellRendererFeature +) => { + if (!cellRendererFeature) return undefined; + const cellRendererGetter = await cellRendererFeature.getRenderer(); + function getCellRenderer(fieldName: string) { + const CellRenderer = cellRendererGetter(fieldName); + if (!CellRenderer) return undefined; + return React.memo(function SecuritySolutionCellRenderer(props: DataGridCellValueElementProps) { + return ; + }); + } + + return getCellRenderer; +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx index 602879125a331..572c86a0e515b 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx @@ -7,25 +7,71 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import React, { FunctionComponent, PropsWithChildren } from 'react'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { RootProfileProvider, SolutionType } from '../../../profiles'; import { ProfileProviderServices } from '../../profile_provider_services'; import { SecurityProfileProviderFactory } from '../types'; +import { createCellRendererAccessor } from '../accessors/get_cell_renderer_accessor'; +import { createAppWrapperAccessor } from '../accessors/create_app_wrapper_accessor'; + +interface SecurityRootProfileContext { + appWrapper?: FunctionComponent>; + getCellRenderer?: ( + fieldName: string + ) => FunctionComponent | undefined; +} + +const EmptyAppWrapper: FunctionComponent> = ({ children }) => <>{children}; export const createSecurityRootProfileProvider: SecurityProfileProviderFactory< - RootProfileProvider -> = (services: ProfileProviderServices) => ({ - profileId: 'security-root-profile', - isExperimental: true, - profile: { - getCellRenderers: (prev) => (params) => ({ - ...prev(params), - }), - }, - resolve: (params) => { - if (params.solutionNavId === SolutionType.Security) { - return { isMatch: true, context: { solutionType: SolutionType.Security } }; - } + RootProfileProvider +> = (services: ProfileProviderServices) => { + const { discoverShared } = services; + const discoverFeaturesRegistry = discoverShared.features.registry; + const cellRendererFeature = discoverFeaturesRegistry.getById('security-solution-cell-renderer'); + const appWrapperFeature = discoverFeaturesRegistry.getById('security-solution-app-wrapper'); + + return { + profileId: 'security-root-profile', + isExperimental: true, + profile: { + getRenderAppWrapper: (PrevWrapper, params) => { + const AppWrapper = params.context.appWrapper ?? EmptyAppWrapper; + return ({ children }) => ( + + {children} + + ); + }, + getCellRenderers: + (prev, { context }) => + (params) => { + const entries = prev(params); + ['host.name', 'user.name', 'source.ip', 'destination.ip'].forEach((fieldName) => { + entries[fieldName] = context.getCellRenderer?.(fieldName) ?? entries[fieldName]; + }); + return entries; + }, + }, + resolve: async (params) => { + if (params.solutionNavId !== SolutionType.Security) { + return { + isMatch: false, + }; + } + + const getAppWrapper = await createAppWrapperAccessor(appWrapperFeature); + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); - return { isMatch: false }; - }, -}); + return { + isMatch: true, + context: { + solutionType: SolutionType.Security, + appWrapper: getAppWrapper?.(), + getCellRenderer, + }, + }; + }, + }; +}; diff --git a/src/plugins/discover/public/context_awareness/types.ts b/src/plugins/discover/public/context_awareness/types.ts index 4b75e6473aafd..70e40df3f8f63 100644 --- a/src/plugins/discover/public/context_awareness/types.ts +++ b/src/plugins/discover/public/context_awareness/types.ts @@ -20,7 +20,7 @@ import type { EuiIconType } from '@elastic/eui/src/components/icon/icon'; import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; import type { OmitIndexSignature } from 'type-fest'; import type { Trigger } from '@kbn/ui-actions-plugin/public'; -import type { PropsWithChildren, ReactElement } from 'react'; +import type { FunctionComponent, PropsWithChildren } from 'react'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import type { DiscoverDataSource } from '../../common/data_sources'; import type { DiscoverAppState } from '../application/main/state_management/discover_app_state_container'; @@ -123,6 +123,10 @@ export interface DefaultAppStateExtension { * * 1-20: number of lines to display */ rowHeight?: number; + /** + * The field to apply for the histogram breakdown + */ + breakdownField?: string; } /** @@ -264,7 +268,7 @@ export interface Profile { * @param props The app wrapper props * @returns The custom app wrapper component */ - getRenderAppWrapper: (props: PropsWithChildren<{}>) => ReactElement; + getRenderAppWrapper: FunctionComponent>; /** * Gets default Discover app state that should be used when the profile is resolved diff --git a/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx b/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx index deea7aa43c9fc..f723ae1ea7495 100644 --- a/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx +++ b/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx @@ -69,7 +69,7 @@ export const SavedSearchEmbeddableBase: FC )} - {children} + {children} {Boolean(append) && {append}} diff --git a/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx b/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx index f6c77dc6cddf5..0a2919fe1540c 100644 --- a/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx +++ b/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx @@ -36,12 +36,13 @@ interface DiscoverGridEmbeddableProps extends Omit void; onRemoveColumn: (column: string) => void; savedSearchId?: string; + enableDocumentViewer: boolean; } export const DiscoverGridMemoized = React.memo(DiscoverGrid); export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { - const { interceptedWarnings, ...gridProps } = props; + const { interceptedWarnings, enableDocumentViewer, ...gridProps } = props; const [expandedDoc, setExpandedDoc] = useState(undefined); @@ -131,7 +132,7 @@ export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { expandedDoc={expandedDoc} showMultiFields={props.services.uiSettings.get(SHOW_MULTIFIELDS)} maxDocFieldsDisplayed={props.services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED)} - renderDocumentView={renderDocumentView} + renderDocumentView={enableDocumentViewer ? renderDocumentView : undefined} renderCustomToolbar={renderCustomToolbarWithElements} externalCustomRenderers={cellRenderers} enableComparisonMode diff --git a/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx b/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx index 44d3c1685cbfe..8375e72aa34de 100644 --- a/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx +++ b/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx @@ -15,7 +15,6 @@ import { DOC_HIDE_TIME_COLUMN_SETTING, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, - isLegacyTableEnabled, } from '@kbn/discover-utils'; import { FetchContext, @@ -28,7 +27,6 @@ import { DataGridDensity, DataLoadingState, useColumns } from '@kbn/unified-data import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { DiscoverGridSettings } from '@kbn/saved-search-plugin/common'; import useObservable from 'react-use/lib/useObservable'; -import { DiscoverDocTableEmbeddable } from '../../components/doc_table/create_doc_table_embeddable'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { getSortForEmbeddable } from '../../utils'; import { getAllowedSampleSize, getMaxAllowedSampleSize } from '../../utils/get_allowed_sample_size'; @@ -49,16 +47,17 @@ interface SavedSearchEmbeddableComponentProps { }; dataView: DataView; onAddFilter?: DocViewFilterFn; + enableDocumentViewer: boolean; stateManager: SearchEmbeddableStateManager; } -const DiscoverDocTableEmbeddableMemoized = React.memo(DiscoverDocTableEmbeddable); const DiscoverGridEmbeddableMemoized = React.memo(DiscoverGridEmbeddable); export function SearchEmbeddableGridComponent({ api, dataView, onAddFilter, + enableDocumentViewer, stateManager, }: SavedSearchEmbeddableComponentProps) { const discoverServices = useDiscoverServices(); @@ -103,14 +102,6 @@ export function SearchEmbeddableGridComponent({ ); const isEsql = useMemo(() => isEsqlMode(savedSearch), [savedSearch]); - const useLegacyTable = useMemo( - () => - isLegacyTableEnabled({ - uiSettings: discoverServices.uiSettings, - isEsqlMode: isEsql, - }), - [discoverServices, isEsql] - ); const sort = useMemo(() => { return getSortForEmbeddable(savedSearch.sort, dataView, discoverServices.uiSettings, isEsql); @@ -231,19 +222,6 @@ export function SearchEmbeddableGridComponent({ useNewFieldsApi, }; - if (useLegacyTable) { - return ( - - ); - } - return ( ); } diff --git a/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx b/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx index 37213b17c377d..4117a36a4e048 100644 --- a/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx +++ b/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx @@ -37,6 +37,7 @@ import { initializeEditApi } from './initialize_edit_api'; import { initializeFetch, isEsqlMode } from './initialize_fetch'; import { initializeSearchEmbeddableApi } from './initialize_search_embeddable_api'; import { + NonPersistedDisplayOptions, SearchEmbeddableApi, SearchEmbeddableRuntimeState, SearchEmbeddableSerializedState, @@ -84,6 +85,11 @@ export const getSearchEmbeddableFactory = ({ initialState?.savedObjectDescription ); + /** By-value SavedSearchComponent package (non-dashboard contexts) state, to adhere to the comparator contract of an embeddable. */ + const nonPersistedDisplayOptions$ = new BehaviorSubject< + NonPersistedDisplayOptions | undefined + >(initialState?.nonPersistedDisplayOptions); + /** All other state */ const blockingError$ = new BehaviorSubject(undefined); const dataLoading$ = new BehaviorSubject(true); @@ -201,6 +207,10 @@ export const getSearchEmbeddableFactory = ({ defaultPanelDescription$, (value) => defaultPanelDescription$.next(value), ], + nonPersistedDisplayOptions: [ + nonPersistedDisplayOptions$, + (value) => nonPersistedDisplayOptions$.next(value), + ], } ); @@ -304,7 +314,18 @@ export const getSearchEmbeddableFactory = ({ diff --git a/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx b/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx index e824fb6fdc021..7b6f20927d347 100644 --- a/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx +++ b/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx @@ -15,8 +15,8 @@ import { ISearchSource, SerializedSearchSourceFields } from '@kbn/data-plugin/co import { DataView } from '@kbn/data-views-plugin/common'; import { DataTableRecord } from '@kbn/discover-utils/types'; import type { - PublishesDataViews, - PublishesUnifiedSearch, + PublishesWritableUnifiedSearch, + PublishesWritableDataViews, StateComparators, } from '@kbn/presentation-publishing'; import { DiscoverGridSettings, SavedSearch } from '@kbn/saved-search-plugin/common'; @@ -71,7 +71,7 @@ export const initializeSearchEmbeddableApi = async ( discoverServices: DiscoverServices; } ): Promise<{ - api: PublishesSavedSearch & PublishesDataViews & Partial; + api: PublishesSavedSearch & PublishesWritableDataViews & Partial; stateManager: SearchEmbeddableStateManager; comparators: StateComparators; cleanup: () => void; @@ -110,6 +110,8 @@ export const initializeSearchEmbeddableApi = async ( searchSource.getField('query') ); + const canEditUnifiedSearch = () => false; + /** This is the state that has to be fetched */ const rows$ = new BehaviorSubject([]); const columnsMeta$ = new BehaviorSubject(undefined); @@ -144,6 +146,25 @@ export const initializeSearchEmbeddableApi = async ( pick(stateManager, EDITABLE_SAVED_SEARCH_KEYS) ); + /** APIs for updating search source properties */ + const setDataViews = (nextDataViews: DataView[]) => { + searchSource.setField('index', nextDataViews[0]); + dataViews.next(nextDataViews); + searchSource$.next(searchSource); + }; + + const setFilters = (filters: Filter[] | undefined) => { + searchSource.setField('filter', filters); + filters$.next(filters); + searchSource$.next(searchSource); + }; + + const setQuery = (query: Query | AggregateQuery | undefined) => { + searchSource.setField('query', query); + query$.next(query); + searchSource$.next(searchSource); + }; + /** Keep the saved search in sync with any state changes */ const syncSavedSearch = combineLatest([onAnyStateChange, searchSource$]) .pipe( @@ -163,10 +184,14 @@ export const initializeSearchEmbeddableApi = async ( syncSavedSearch.unsubscribe(); }, api: { + setDataViews, dataViews, savedSearch$, filters$, + setFilters, query$, + setQuery, + canEditUnifiedSearch, }, stateManager, comparators: { diff --git a/src/plugins/discover/public/embeddable/types.ts b/src/plugins/discover/public/embeddable/types.ts index 1b7ab4a96c2de..64cf5a390da3a 100644 --- a/src/plugins/discover/public/embeddable/types.ts +++ b/src/plugins/discover/public/embeddable/types.ts @@ -15,10 +15,9 @@ import { HasInPlaceLibraryTransforms, PublishesBlockingError, PublishesDataLoading, - PublishesDataViews, PublishesSavedObjectId, - PublishesUnifiedSearch, PublishesWritablePanelTitle, + PublishesWritableUnifiedSearch, PublishingSubject, SerializedTimeRange, SerializedTitles, @@ -30,6 +29,7 @@ import { } from '@kbn/saved-search-plugin/common/types'; import { DataTableColumnsMeta } from '@kbn/unified-data-table'; import { BehaviorSubject } from 'rxjs'; +import { PublishesWritableDataViews } from '@kbn/presentation-publishing/interfaces/publishes_data_views'; import { EDITABLE_SAVED_SEARCH_KEYS } from './constants'; export type SearchEmbeddableState = Pick< @@ -59,6 +59,13 @@ export type SearchEmbeddableSerializedAttributes = Omit< > & Pick; +// These are options that are not persisted in the saved object, but can be used by solutions +// when utilising the SavedSearchComponent package outside of dashboard contexts. +export interface NonPersistedDisplayOptions { + enableDocumentViewer?: boolean; + enableFilters?: boolean; +} + export type SearchEmbeddableSerializedState = SerializedTitles & SerializedTimeRange & Partial> & { @@ -66,6 +73,7 @@ export type SearchEmbeddableSerializedState = SerializedTitles & attributes?: SavedSearchAttributes & { references: SavedSearch['references'] }; // by reference savedObjectId?: string; + nonPersistedDisplayOptions?: NonPersistedDisplayOptions; }; export type SearchEmbeddableRuntimeState = SearchEmbeddableSerializedAttributes & @@ -74,20 +82,20 @@ export type SearchEmbeddableRuntimeState = SearchEmbeddableSerializedAttributes savedObjectTitle?: string; savedObjectId?: string; savedObjectDescription?: string; + nonPersistedDisplayOptions?: NonPersistedDisplayOptions; }; export type SearchEmbeddableApi = DefaultEmbeddableApi< SearchEmbeddableSerializedState, SearchEmbeddableRuntimeState > & - PublishesDataViews & PublishesSavedObjectId & PublishesDataLoading & PublishesBlockingError & PublishesWritablePanelTitle & PublishesSavedSearch & - PublishesDataViews & - PublishesUnifiedSearch & + PublishesWritableDataViews & + PublishesWritableUnifiedSearch & HasInPlaceLibraryTransforms & HasTimeRange & Partial; diff --git a/src/plugins/discover/public/embeddable/utils/serialization_utils.ts b/src/plugins/discover/public/embeddable/utils/serialization_utils.ts index 191a37fe3326e..f193d52054a3c 100644 --- a/src/plugins/discover/public/embeddable/utils/serialization_utils.ts +++ b/src/plugins/discover/public/embeddable/utils/serialization_utils.ts @@ -67,6 +67,7 @@ export const deserializeState = async ({ return { ...savedSearch, ...panelState, + nonPersistedDisplayOptions: serializedState.rawState.nonPersistedDisplayOptions, }; } }; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index b5d4308010f1f..b54665bdc50a0 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -35,6 +35,10 @@ export { type PublishesSavedSearch, type HasTimeRange, type SearchEmbeddableSerializedState, + type SearchEmbeddableRuntimeState, + type SearchEmbeddableApi, + type NonPersistedDisplayOptions, } from './embeddable'; export { loadSharingDataHelpers } from './utils'; export { LogsExplorerTabs, type LogsExplorerTabsProps } from './components/logs_explorer_tabs'; +export type { DiscoverServices } from './build_services'; diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 0ee80da03a7d1..e29922d05f2c0 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -21,14 +21,13 @@ import { import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { ENABLE_ESQL } from '@kbn/esql-utils'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; -import { SEARCH_EMBEDDABLE_TYPE, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; +import { SEARCH_EMBEDDABLE_TYPE } from '@kbn/discover-utils'; import { SavedSearchAttributes, SavedSearchType } from '@kbn/saved-search-plugin/common'; import { i18n } from '@kbn/i18n'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; import { ViewSavedSearchAction } from './embeddable/actions/view_saved_search_action'; -import { injectTruncateStyles } from './utils/truncate_styles'; import { initializeKbnUrlTracking } from './utils/initialize_kbn_url_tracking'; import { DiscoverContextAppLocator, @@ -285,7 +284,6 @@ export class DiscoverPlugin plugins.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction); plugins.uiActions.registerTrigger(SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER); plugins.uiActions.registerTrigger(DISCOVER_CELL_ACTIONS_TRIGGER); - injectTruncateStyles(core.uiSettings.get(TRUNCATE_MAX_HEIGHT)); const isEsqlEnabled = core.uiSettings.get(ENABLE_ESQL); diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index 2ef380db98703..4b16e3e58df7c 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -42,7 +42,7 @@ import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; -import { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; +import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import { DiscoverAppLocator } from '../common'; import { DiscoverCustomizationContext } from './customizations'; import { type DiscoverContainerProps } from './components/discover_container'; diff --git a/src/plugins/discover/public/utils/truncate_styles.ts b/src/plugins/discover/public/utils/truncate_styles.ts deleted file mode 100644 index 953144c4b90c3..0000000000000 --- a/src/plugins/discover/public/utils/truncate_styles.ts +++ /dev/null @@ -1,48 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import createCache from '@emotion/cache'; -import { cache } from '@emotion/css'; -import { serializeStyles } from '@emotion/serialize'; - -/** - * The following emotion cache management was introduced here - * https://ntsim.uk/posts/how-to-update-or-remove-global-styles-in-emotion/ - */ -const TRUNCATE_GRADIENT_HEIGHT = 15; -const globalThemeCache = createCache({ key: 'truncation' }); - -const buildStylesheet = (maxHeight: number) => { - if (!maxHeight) { - return [ - ` - .dscTruncateByHeight { - max-height: none; - }`, - ]; - } - return [ - ` - .dscTruncateByHeight { - overflow: hidden; - max-height: ${maxHeight}px !important; - } - .dscTruncateByHeight:before { - top: ${maxHeight - TRUNCATE_GRADIENT_HEIGHT}px; - } - `, - ]; -}; - -export const injectTruncateStyles = (maxHeight: number) => { - const serialized = serializeStyles(buildStylesheet(maxHeight), cache.registered); - if (!globalThemeCache.inserted[serialized.name]) { - globalThemeCache.insert('', serialized, globalThemeCache.sheet, true); - } -}; diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index 9d0905b27bfad..7dd84c9728696 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -23,13 +23,10 @@ import { CONTEXT_DEFAULT_SIZE_SETTING, CONTEXT_STEP_SETTING, CONTEXT_TIE_BREAKER_FIELDS_SETTING, - DOC_TABLE_LEGACY, MODIFY_COLUMNS_ON_SWITCH, SEARCH_FIELDS_FROM_SOURCE, MAX_DOC_FIELDS_DISPLAYED, SHOW_MULTIFIELDS, - TRUNCATE_MAX_HEIGHT, - TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE, SHOW_FIELD_STATISTICS, ROW_HEIGHT_OPTION, } from '@kbn/discover-utils'; @@ -183,42 +180,6 @@ export const getUiSettings: ( category: ['discover'], schema: schema.arrayOf(schema.string()), }, - [DOC_TABLE_LEGACY]: { - name: i18n.translate('discover.advancedSettings.disableDocumentExplorer', { - defaultMessage: 'Document Explorer or classic view', - }), - value: false, - description: i18n.translate('discover.advancedSettings.disableDocumentExplorerDescription', { - defaultMessage: - 'To use the new {documentExplorerDocs} instead of the classic view, turn off this option. ' + - 'The Document Explorer offers better data sorting, resizable columns, and a full screen view.', - values: { - documentExplorerDocs: - `` + - i18n.translate('discover.advancedSettings.documentExplorerLinkText', { - defaultMessage: 'Document Explorer', - }) + - '', - }, - }), - requiresPageReload: true, - category: ['discover'], - schema: schema.boolean(), - metric: { - type: METRIC_TYPE.CLICK, - name: 'discover:useLegacyDataGrid', - }, - deprecation: { - message: i18n.translate( - 'discover.advancedSettings.discover.disableDocumentExplorerDeprecation', - { - defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', - } - ), - docLinksKey: 'discoverSettings', - }, - }, [MODIFY_COLUMNS_ON_SWITCH]: { name: i18n.translate('discover.advancedSettings.discover.modifyColumnsOnSwitchTitle', { defaultMessage: 'Modify columns when changing data views', @@ -316,23 +277,4 @@ export const getUiSettings: ( }), schema: schema.number({ min: -1 }), }, - [TRUNCATE_MAX_HEIGHT]: { - name: i18n.translate('discover.advancedSettings.params.maxCellHeightTitle', { - defaultMessage: 'Maximum cell height in the classic table', - }), - value: TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE, - category: ['discover'], - description: i18n.translate('discover.advancedSettings.params.maxCellHeightText', { - defaultMessage: - 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.', - }), - schema: schema.number({ min: 0 }), - requiresPageReload: true, - deprecation: { - message: i18n.translate('discover.advancedSettings.discover.maxCellHeightDeprecation', { - defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', - }), - docLinksKey: 'discoverSettings', - }, - }, }); diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 1bb3aa10acce0..36655983db13a 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -95,9 +95,9 @@ "@kbn/presentation-containers", "@kbn/observability-ai-assistant-plugin", "@kbn/fields-metadata-plugin", + "@kbn/discover-contextual-components", "@kbn/logs-data-access-plugin", "@kbn/core-lifecycle-browser", - "@kbn/discover-contextual-components", "@kbn/esql-ast", "@kbn/discover-shared-plugin" ], diff --git a/src/plugins/discover_shared/public/index.ts b/src/plugins/discover_shared/public/index.ts index f58a9eaf44f84..4be7a75c817a8 100644 --- a/src/plugins/discover_shared/public/index.ts +++ b/src/plugins/discover_shared/public/index.ts @@ -17,5 +17,9 @@ export type { DiscoverSharedPublicSetup, DiscoverSharedPublicStart } from './typ export type { ObservabilityLogsAIAssistantFeatureRenderDeps, ObservabilityLogsAIAssistantFeature, + SecuritySolutionCellRendererFeature, + SecuritySolutionAppWrapperFeature, DiscoverFeature, -} from './services/discover_features'; + DiscoverFeaturesServiceSetup, + DiscoverFeaturesServiceStart, +} from './services/discover_features/types'; diff --git a/src/plugins/discover_shared/public/services/discover_features/types.ts b/src/plugins/discover_shared/public/services/discover_features/types.ts index cdf78b3335507..a40a4f87a3eb9 100644 --- a/src/plugins/discover_shared/public/services/discover_features/types.ts +++ b/src/plugins/discover_shared/public/services/discover_features/types.ts @@ -7,7 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DataTableRecord } from '@kbn/discover-utils'; +import type { DataTableRecord } from '@kbn/discover-utils'; +import type { FunctionComponent, PropsWithChildren } from 'react'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { FeaturesRegistry } from '../../../common'; /** @@ -38,8 +40,31 @@ export interface ObservabilityCreateSLOFeature { }) => React.ReactNode; } +/** **************** Security Solution ****************/ + +export interface SecuritySolutionCellRendererFeature { + id: 'security-solution-cell-renderer'; + getRenderer: () => Promise< + (fieldName: string) => FunctionComponent | undefined + >; +} + +export interface SecuritySolutionAppWrapperFeature { + id: 'security-solution-app-wrapper'; + getWrapper: () => Promise<() => FunctionComponent>>; +} + +export type SecuritySolutionFeature = + | SecuritySolutionCellRendererFeature + | SecuritySolutionAppWrapperFeature; + +/** ****************************************************************************************/ + // This should be a union of all the available client features. -export type DiscoverFeature = ObservabilityLogsAIAssistantFeature | ObservabilityCreateSLOFeature; +export type DiscoverFeature = + | ObservabilityLogsAIAssistantFeature + | ObservabilityCreateSLOFeature + | SecuritySolutionFeature; /** * Service types diff --git a/src/plugins/discover_shared/tsconfig.json b/src/plugins/discover_shared/tsconfig.json index 9d2b07eb7aae9..d8bda5214c747 100644 --- a/src/plugins/discover_shared/tsconfig.json +++ b/src/plugins/discover_shared/tsconfig.json @@ -13,5 +13,6 @@ "kbn_references": [ "@kbn/discover-utils", "@kbn/core", + "@kbn/unified-data-table", ] } diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx index 82516423424f6..e48e5192f189e 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx @@ -65,7 +65,7 @@ export const DynamicFields = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -155,7 +155,7 @@ export const DynamicFieldsValidation = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -218,7 +218,7 @@ export const DynamicFieldsReorder = () => { return ( -
+
@@ -245,7 +245,7 @@ export const DynamicFieldsReorder = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -273,4 +273,4 @@ export const DynamicFieldsReorder = () => { ); }; -``` \ No newline at end of file +``` diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx index 7e7cce5e81332..0851440400814 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx @@ -7,8 +7,8 @@ tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- -If your form does not have a fix set of fields (single interface) and you need to add/remove fields dynamically, you can leverage the power of field composition with the form lib. It let's you swap fields in your form whenever needed. Any field that **is not in the DOM** is automatically cleared when unmounting and its value won't be returned in the form data. -If you _do_ need to keep a field value, but hide the field in the UI, then you need to use CSS (`
...
`) +If your form does not have a fix set of fields (single interface) and you need to add/remove fields dynamically, you can leverage the power of field composition with the form lib. It let's you swap fields in your form whenever needed. Any field that **is not in the DOM** is automatically cleared when unmounting and its value won't be returned in the form data. +If you _do_ need to keep a field value, but hide the field in the UI, then you need to use CSS (`
...
`) Imagine you're building an app that lets people buy a car online. You want to build a form that lets the user select the model of the car (`sedan`, `golf cart`, `clown mobile`), and based on their selection you'll show a different form for configuring the selected model's options. diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx index dd3b402e85e3f..3ab849d262db2 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx @@ -90,7 +90,7 @@ export const SerializersAndDeserializers = () => { {/* We don't remove it from the DOM as we would lose the value entered in the field. */} -
+
diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx index f920eb91ea3cc..b777ecd4a85b8 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx @@ -43,7 +43,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -51,7 +51,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -59,7 +59,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -70,7 +70,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -78,7 +78,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -86,7 +86,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -188,7 +188,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, @@ -303,7 +303,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -311,7 +311,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -319,7 +319,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -330,7 +330,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -338,7 +338,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -346,7 +346,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -448,7 +448,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx index 83beef1fc8387..098919fb96c2a 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx @@ -46,7 +46,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -54,7 +54,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -62,7 +62,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -73,7 +73,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -81,7 +81,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -89,7 +89,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -223,7 +223,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, @@ -384,7 +384,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -392,7 +392,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -400,7 +400,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -411,7 +411,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -419,7 +419,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -427,7 +427,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -561,7 +561,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx index fb56fded77e3a..807412a33a92b 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx @@ -87,7 +87,7 @@ export function Reorder() {
@@ -214,7 +214,7 @@ const MyFormComponent = () => {
diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx index c24df488ce8a0..18b4cf2fd1d48 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx @@ -98,7 +98,7 @@ const getPropsForType = (type: FieldType) => { { value: 'warning', inputDisplay: ( - + Warning ), @@ -107,7 +107,7 @@ const getPropsForType = (type: FieldType) => { { value: 'minor', inputDisplay: ( - + Minor ), @@ -115,7 +115,7 @@ const getPropsForType = (type: FieldType) => { { value: 'critical', inputDisplay: ( - + Critical ), diff --git a/src/plugins/esql_datagrid/public/create_datagrid.tsx b/src/plugins/esql_datagrid/public/create_datagrid.tsx index 7df7d84fb8080..4c281519edfb8 100644 --- a/src/plugins/esql_datagrid/public/create_datagrid.tsx +++ b/src/plugins/esql_datagrid/public/create_datagrid.tsx @@ -44,7 +44,7 @@ export const ESQLDataGrid = (props: ESQLDataGridProps) => { }, []); const getWrapper = (children: JSX.Element) => { - return props.fullHeight ?
{children}
: <>{children}; + return props.fullHeight ?
{children}
: <>{children}; }; const deps = value?.[0]; diff --git a/src/plugins/expression_error/public/components/error/error.tsx b/src/plugins/expression_error/public/components/error/error.tsx index fac0ee484fb06..93e10470c320e 100644 --- a/src/plugins/expression_error/public/components/error/error.tsx +++ b/src/plugins/expression_error/public/components/error/error.tsx @@ -40,14 +40,14 @@ export const Error: FC = ({ payload, onClose }) => { return (

{message ? strings.getDescription() : ''}

{message && ( -

+

{message}

)} diff --git a/src/plugins/expression_error/public/components/error/show_debugging.tsx b/src/plugins/expression_error/public/components/error/show_debugging.tsx index ddb9cbeea7a19..49ef1acb90d3d 100644 --- a/src/plugins/expression_error/public/components/error/show_debugging.tsx +++ b/src/plugins/expression_error/public/components/error/show_debugging.tsx @@ -24,7 +24,7 @@ export const ShowDebugging: FC = ({ payload }) => { See Details {expanded && ( -
+
)} diff --git a/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx b/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx index bdc28e714cd8f..82b21e60c8453 100644 --- a/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx +++ b/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx @@ -94,7 +94,7 @@ export function RepeatImageComponent({ } return ( -
+
{imagesToRender}
); diff --git a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx index 32c7d85fa5695..eb9bc34d40b3e 100644 --- a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx @@ -61,7 +61,7 @@ export function ReactExpressionRenderer({
{isEmpty && } {isLoading && ( - + )} {!isLoading && error && renderError?.(error.message, error)}
diff --git a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts index 16fd2e535763b..f0b33953caf2e 100644 --- a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts +++ b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts @@ -19,8 +19,8 @@ describe('ES-index-backed file client', () => { let esClient: TestEnvironmentUtils['esClient']; let fileClient: FileClient; let testHarness: TestEnvironmentUtils; - const blobStorageIndex = '.kibana-test-blob'; - const metadataIndex = '.kibana-test-metadata'; + const blobStorageIndex = 'kibana-files-test-blob'; + const metadataIndex = 'kibana-files-test-metadata'; const deleteFile = async ({ id, diff --git a/src/plugins/files/server/test_utils/setup_integration_environment.ts b/src/plugins/files/server/test_utils/setup_integration_environment.ts index e5a9ff9ffd339..369f39867f609 100644 --- a/src/plugins/files/server/test_utils/setup_integration_environment.ts +++ b/src/plugins/files/server/test_utils/setup_integration_environment.ts @@ -21,7 +21,7 @@ export type TestEnvironmentUtils = Awaited )} - + {description &&

{description}

}
diff --git a/src/plugins/home/public/application/components/recently_accessed.js b/src/plugins/home/public/application/components/recently_accessed.js index e873b5eda5996..be9d8d0ac1923 100644 --- a/src/plugins/home/public/application/components/recently_accessed.js +++ b/src/plugins/home/public/application/components/recently_accessed.js @@ -58,7 +58,7 @@ export class RecentlyAccessed extends Component { for (let i = NUM_LONG_LINKS; i < this.props.recentlyAccessed.length; i++) { dropdownLinks.push(
  • diff --git a/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap b/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap index 5235392121ab0..b11a936807c9f 100644 --- a/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap +++ b/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap @@ -7,7 +7,7 @@ exports[`render 1`] = ` paddingSize="none" > - {this.renderTabs()} + {this.renderTabs()} {this.renderHeader()} diff --git a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx index 1a5ee3bc64e1d..0a680e317dc72 100644 --- a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx +++ b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx @@ -205,7 +205,7 @@ export function ImageEditorFlyout(props: ImageEditorFlyoutProps) {
  • } /> -

    +

    setIsFilePickerOpen(true)} data-test-subj="imageEmbeddableEditorSelectFiles" diff --git a/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx b/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx index 4eb8edc0a0695..ff4b2233a97d3 100644 --- a/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx +++ b/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx @@ -126,7 +126,7 @@ export function ImageViewer({ )} {onClear && ( { } return ( - + {controlComponent} ); diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap index e063ccea48cc2..42b8d1a99c1dc 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap @@ -2,13 +2,13 @@ exports[`render partial should display callout when request timed out 1`] = ` + {clusterDetails.timed_out ? ( - + {host} diff --git a/src/plugins/interactive_setup/public/enrollment_token_form.tsx b/src/plugins/interactive_setup/public/enrollment_token_form.tsx index 65765291fb79a..3cfc7d3fe33a2 100644 --- a/src/plugins/interactive_setup/public/enrollment_token_form.tsx +++ b/src/plugins/interactive_setup/public/enrollment_token_form.tsx @@ -184,7 +184,7 @@ const EnrollmentTokenDetails: FunctionComponent = ( defaultMessage="Connect to" /> - + {token.adr[0]} diff --git a/src/plugins/interactive_setup/public/single_chars_field.tsx b/src/plugins/interactive_setup/public/single_chars_field.tsx index 27bb6ce3e60a0..13af3f1f7ba3f 100644 --- a/src/plugins/interactive_setup/public/single_chars_field.tsx +++ b/src/plugins/interactive_setup/public/single_chars_field.tsx @@ -73,13 +73,13 @@ export const SingleCharsField: FunctionComponent = ({ ); } children.push( - + { inputRefs.current[i] = el; @@ -125,7 +125,7 @@ export const SingleCharsField: FunctionComponent = ({ }} maxLength={1} isInvalid={isInvalid} - style={{ textAlign: 'center' }} + css={{ textAlign: 'center' }} aria-label={i18n.translate('interactiveSetup.singleCharsField.digitLabel', { defaultMessage: 'Digit {index}', values: { index: i + 1 }, diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx index 3631ae86e1ec3..228e6d5f8cb15 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx @@ -23,7 +23,7 @@ export const ActionCards = ({ actionCards }: ActionCardsProps) => { )); return ( - + {cards} ); diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap index 9782a4cf1da65..fdee5059e7876 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap @@ -27,8 +27,7 @@ exports[`ElasticAgentCard props button 1`] = ` image={ } @@ -78,8 +78,7 @@ exports[`ElasticAgentCard props category 1`] = ` image={ } @@ -129,8 +129,7 @@ exports[`ElasticAgentCard props href 1`] = ` image={ } @@ -185,8 +185,7 @@ exports[`ElasticAgentCard props recommended 1`] = ` image={ } @@ -236,8 +236,7 @@ exports[`ElasticAgentCard renders 1`] = ` image={ } diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx index c4849e814edd4..1c8169ac5a732 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx @@ -43,7 +43,7 @@ export const ElasticAgentCard: FunctionComponent = ({ const image = ( = { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, }, - 'truncate:maxHeight': { - type: 'long', - _meta: { description: 'Non-default value of setting.' }, - }, 'timepicker:timeDefaults': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, @@ -424,10 +420,6 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'doc_table:legacy': { - type: 'boolean', - _meta: { description: 'Non-default value of setting.' }, - }, 'discover:modifyColumnsOnSwitch': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 9796436007357..4c6f17a85914c 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -30,7 +30,6 @@ export interface UsageStats { 'autocomplete:valueSuggestionMethod': string; 'search:timeout': number; 'visualization:visualize:legacyHeatmapChartsLibrary': boolean; - 'doc_table:legacy': boolean; 'discover:modifyColumnsOnSwitch': boolean; 'discover:searchFieldsFromSource': boolean; 'discover:showFieldStatistics': boolean; @@ -101,7 +100,6 @@ export interface UsageStats { 'fileUpload:maxFileSize': string; 'ml:anomalyDetection:results:enableTimeDefaults': boolean; 'ml:anomalyDetection:results:timeDefaults': string; - 'truncate:maxHeight': number; 'timepicker:timeDefaults': string; 'timepicker:refreshIntervalDefaults': string; 'timepicker:quickRanges': string; diff --git a/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx b/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx index b29563713d365..7954a7f7dfc65 100644 --- a/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx +++ b/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx @@ -393,7 +393,7 @@ export const PresentationPanelHoverActions = ({ notification.execute({ embeddable: api, trigger: panelNotificationTrigger }) } diff --git a/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx b/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx index b48a4eca7ae1f..795fd6b566a9b 100644 --- a/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx +++ b/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx @@ -167,7 +167,7 @@ export const usePresentationPanelHeaderActions = < notification.execute({ embeddable: api, trigger: panelNotificationTrigger }) } diff --git a/src/plugins/presentation_util/public/components/labs/environment_switch.tsx b/src/plugins/presentation_util/public/components/labs/environment_switch.tsx index 94e71fe432fc5..d8727b4e2dbae 100644 --- a/src/plugins/presentation_util/public/components/labs/environment_switch.tsx +++ b/src/plugins/presentation_util/public/components/labs/environment_switch.tsx @@ -44,13 +44,13 @@ export const EnvironmentSwitch = ({ env, isChecked, onChange, name }: Props) => const canSet = env === 'kibana' ? canSetAdvancedSettings : true; return ( - + @@ -63,7 +63,7 @@ export const EnvironmentSwitch = ({ env, isChecked, onChange, name }: Props) => compressed /> - + diff --git a/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx b/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx index 1d454050963d9..8da1fe97455a6 100644 --- a/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx +++ b/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx @@ -34,7 +34,7 @@ export const LabsBeakerButton = ({ solutions, ...props }: Props) => { {overrideCount > 0 ? ( - + {overrideCount} ) : null} diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index 4e29f34dedb73..575f13b66b59a 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -326,7 +326,7 @@ export class FlyoutClass extends Component< ), render: (list: any[]) => { return ( -

      +
        {take(list, 3).map((obj, key) => (
      • {obj.title}
      • ))} diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index fe0f599dd6ca1..35e0242b57624 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10492,12 +10492,6 @@ "description": "Non-default value of setting." } }, - "truncate:maxHeight": { - "type": "long", - "_meta": { - "description": "Non-default value of setting." - } - }, "timepicker:timeDefaults": { "type": "keyword", "_meta": { @@ -10765,12 +10759,6 @@ "description": "Non-default value of setting." } }, - "doc_table:legacy": { - "type": "boolean", - "_meta": { - "description": "Non-default value of setting." - } - }, "discover:modifyColumnsOnSwitch": { "type": "boolean", "_meta": { diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 445f780c07c53..82db03ed08ed5 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -29,9 +29,8 @@ import type { TelemetryCollectionManagerPluginStart } from '@kbn/telemetry-colle import { type PluginInitializerContext, type Logger, - type SavedObjectsClientContract, - SavedObjectsClient, type CoreStart, + type ISavedObjectsRepository, } from '@kbn/core/server'; import { getTelemetryChannelEndpoint } from '../common/telemetry_config'; import { @@ -77,7 +76,7 @@ export class FetcherTask { private readonly subscriptions = new Subscription(); private readonly isOnline$ = new BehaviorSubject(false); // Let's initially assume we are not online private readonly lastReported$ = new BehaviorSubject(0); - private internalRepository?: SavedObjectsClientContract; + private internalRepository?: ISavedObjectsRepository; private telemetryCollectionManager?: TelemetryCollectionManagerPluginStart; constructor(initializerContext: PluginInitializerContext) { @@ -87,9 +86,7 @@ export class FetcherTask { } public start({ savedObjects }: CoreStart, { telemetryCollectionManager }: FetcherTaskDepsStart) { - this.internalRepository = new SavedObjectsClient( - savedObjects.createInternalRepository([TELEMETRY_SAVED_OBJECT_TYPE]) - ); + this.internalRepository = savedObjects.createInternalRepository([TELEMETRY_SAVED_OBJECT_TYPE]); this.telemetryCollectionManager = telemetryCollectionManager; this.subscriptions.add(this.validateConnectivity()); diff --git a/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx index db3a0b8845420..009016a63a906 100644 --- a/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx @@ -187,7 +187,7 @@ const TriggerPicker: React.FC = ({ ), }} - style={{ maxWidth: `80%` }} + css={{ maxWidth: `80%` }} > {triggers.map((trigger) => ( diff --git a/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx b/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx index cfe7784ec99fd..7b48712ff7d64 100644 --- a/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx +++ b/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx @@ -263,7 +263,7 @@ export function Demo({ getTriggerInfo={mockGetTriggerInfo} triggers={[VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER, SELECT_RANGE_TRIGGER]} /> -
        +

        Action Factory Id: {state.currentActionFactory?.id}
        Action Factory Config: {JSON.stringify(state.config)}
        diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx index 1859067212cb9..17c9aa98aa6e1 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx @@ -81,7 +81,7 @@ export const DrilldownTable: React.FC = ({ title={drilldown.error} aria-label={drilldown.error} data-test-subj={`drilldownError-${drilldown.id}`} - style={{ marginLeft: '4px' }} /* a bit of spacing from text */ + css={{ marginLeft: '4px' }} /* a bit of spacing from text */ /> )} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx index c918dbdef215a..cb23fa2d576d8 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx @@ -58,8 +58,8 @@ export const DrilldownTemplateTable: React.FC = ({ name: txtNameColumnTitle, sortable: true, render: (omit, item: DrilldownTemplateTableItem) => ( -
        -
        {item.name}
        +
        +
        {item.name}
        {item.description} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx index 246cf5d7362ba..23633a52be35d 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx @@ -45,7 +45,7 @@ export const FlyoutFrame: FC> = ({ {onBack && ( -
        +
        > = ({ )} {!!children && ( - + {tooltip ? ( {children} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx index 35bdcbe4d2c9f..1c4653b3e8630 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx @@ -74,7 +74,7 @@ export const TriggerPicker: React.FC = ({ ), }} - style={{ maxWidth: `80%` }} + css={{ maxWidth: `80%` }} > {items.map((trigger) => ( data-test-subj="urlDrilldownAdditionalOptions" > - + { diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx index 656ff07623dc5..e308969881429 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx @@ -74,7 +74,7 @@ export const VariablePopover: React.FC = ({ variables, onSelect, variable }} > {(list, search) => ( -
        +
        {search} {list} {variablesHelpLink && ( diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx index 5e97ff9cc55da..a3f70c2badc0c 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx @@ -32,31 +32,17 @@ describe('getHeight', () => { test('when using document explorer, returning the available height in the flyout', () => { const monacoMock = getMonacoMock(500, 0); - const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); + const height = getHeight(monacoMock, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(484); - const heightCustom = getHeight(monacoMock, true, 80); + const heightCustom = getHeight(monacoMock, 80); expect(heightCustom).toBe(420); }); test('when using document explorer, returning the available height in the flyout has a minimun guarenteed height', () => { const monacoMock = getMonacoMock(500); - const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); + const height = getHeight(monacoMock, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(400); }); - - test('when using classic table, its displayed inline without scrolling', () => { - const monacoMock = getMonacoMock(100); - - const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); - expect(height).toBe(1020); - }); - - test('when using classic table, limited height > 500 lines to allow scrolling', () => { - const monacoMock = getMonacoMock(1000); - - const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); - expect(height).toBe(5020); - }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx index 514c994e5d423..68619b6048338 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx @@ -8,7 +8,7 @@ */ import { monaco } from '@kbn/monaco'; -import { MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; +import { MIN_HEIGHT } from './source'; // Displayed margin of the tab content to the window bottom export const DEFAULT_MARGIN_BOTTOM = 16; @@ -28,7 +28,6 @@ export function getTabContentAvailableHeight( export function getHeight( editor: monaco.editor.IStandaloneCodeEditor, - useDocExplorer: boolean, decreaseAvailableHeightBy: number ) { const editorElement = editor?.getDomNode(); @@ -36,17 +35,6 @@ export function getHeight( return 0; } - let result; - if (useDocExplorer) { - result = getTabContentAvailableHeight(editorElement, decreaseAvailableHeightBy); - } else { - // takes care of the classic table, display a maximum of 500 lines - // why not display it all? Due to performance issues when the browser needs to render it all - const lineHeight = editor.getOption(monaco.editor.EditorOption.lineHeight); - const lineCount = editor.getModel()?.getLineCount() || 1; - const displayedLineCount = - lineCount > MAX_LINES_CLASSIC_TABLE ? MAX_LINES_CLASSIC_TABLE : lineCount; - result = editor.getTopForLineNumber(displayedLineCount + 1) + lineHeight; - } + const result = getTabContentAvailableHeight(editorElement, decreaseAvailableHeightBy); return Math.max(result, MIN_HEIGHT); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 5b4ba36cd03f1..3bd1137cabccf 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { ElasticRequestState } from '@kbn/unified-doc-viewer'; -import { isLegacyTableEnabled, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; +import { SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; import { omit } from 'lodash'; import { getUnifiedDocViewerServices } from '../../plugin'; import { useEsDocSearch } from '../../hooks'; @@ -36,9 +36,6 @@ interface SourceViewerProps { onRefresh: () => void; } -// Ihe number of lines displayed without scrolling used for classic table, which renders the component -// inline limitation was necessary to enable virtualized scrolling, which improves performance -export const MAX_LINES_CLASSIC_TABLE = 500; // Minimum height for the source content to guarantee minimum space when the flyout is scrollable. export const MIN_HEIGHT = 400; @@ -57,10 +54,6 @@ export const DocViewerSource = ({ const [jsonValue, setJsonValue] = useState(''); const { uiSettings } = getUnifiedDocViewerServices(); const useNewFieldsApi = !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE); - const useDocExplorer = !isLegacyTableEnabled({ - uiSettings, - isEsqlMode: Array.isArray(textBasedHits), - }); const [requestState, hit] = useEsDocSearch({ id, index, @@ -75,9 +68,7 @@ export const DocViewerSource = ({ } }, [requestState, hit]); - // setting editor height - // - classic view: based on lines height and count to stretch and fit its content - // - explorer: to fill the available space of the document flyout + // setting editor height to fill the available space of the document flyout useEffect(() => { if (!editor) { return; @@ -88,11 +79,7 @@ export const DocViewerSource = ({ return; } - const height = getHeight( - editor, - useDocExplorer, - decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM - ); + const height = getHeight(editor, decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM); if (height === 0) { return; } @@ -102,7 +89,7 @@ export const DocViewerSource = ({ } else { setEditorHeight(height); } - }, [editor, jsonValue, useDocExplorer, setEditorHeight, decreaseAvailableHeightBy]); + }, [editor, jsonValue, setEditorHeight, decreaseAvailableHeightBy]); const loadingState = (
        diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx deleted file mode 100644 index 43f2d21eb8fd1..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx +++ /dev/null @@ -1,452 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { DocViewerLegacyTable } from './table'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import { setUnifiedDocViewerServices } from '../../../plugin'; -import type { UnifiedDocViewerServices } from '../../../types'; - -const services = { - uiSettings: { - get: (key: string) => { - if (key === 'discover:showMultiFields') { - return true; - } - }, - }, - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, -}; - -const dataView = { - fields: { - getAll: () => [ - { - name: '_index', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'message', - type: 'string', - scripted: false, - filterable: false, - }, - { - name: 'extension', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'bytes', - type: 'number', - scripted: false, - filterable: true, - }, - { - name: 'scripted', - type: 'number', - scripted: true, - filterable: false, - }, - ], - }, - metaFields: ['_index', '_score'], - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), -} as unknown as DataView; - -dataView.fields.getByName = (name: string) => { - return dataView.fields.getAll().find((field) => field.name === name); -}; - -const mountComponent = ( - props: DocViewRenderProps, - overrides?: Partial -) => { - setUnifiedDocViewerServices({ ...services, ...overrides } as UnifiedDocViewerServices); - return mountWithIntl(); -}; - -describe('DocViewTable at Discover', () => { - // At Discover's main view, all buttons are rendered - // check for existence of action buttons and warnings - - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ - Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ - et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ - ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ - Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, \ - rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ - Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ - Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', - extension: 'html', - not_mapped: 'yes', - bytes: 100, - objectArray: [{ foo: true }], - relatedContent: { - test: 1, - }, - scripted: 123, - _underscore: 123, - }, - }, - dataView - ); - - const props = { - hit, - columns: ['extension'], - dataView, - filter: jest.fn(), - onAddColumn: jest.fn(), - onRemoveColumn: jest.fn(), - }; - const component = mountComponent(props); - [ - { - _property: '_index', - addInclusiveFilterButton: true, - noMappingWarning: false, - toggleColumnButton: true, - underscoreWarning: false, - }, - { - _property: 'message', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underscoreWarning: false, - }, - { - _property: '_underscore', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underScoreWarning: true, - }, - { - _property: 'scripted', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underScoreWarning: false, - }, - { - _property: 'not_mapped', - addInclusiveFilterButton: false, - noMappingWarning: true, - toggleColumnButton: true, - underScoreWarning: false, - }, - ].forEach((check) => { - const rowComponent = findTestSubject(component, `tableDocViewRow-${check._property}`); - - it(`renders row for ${check._property}`, () => { - expect(rowComponent.length).toBe(1); - }); - - (['addInclusiveFilterButton', 'toggleColumnButton', 'underscoreWarning'] as const).forEach( - (element) => { - const elementExist = check[element]; - - if (typeof elementExist === 'boolean') { - const btn = findTestSubject(rowComponent, element, '^='); - - it(`renders ${element} for '${check._property}' correctly`, () => { - const disabled = btn.length ? btn.props().disabled : true; - const clickAble = btn.length && !disabled ? true : false; - expect(clickAble).toBe(elementExist); - }); - } - } - ); - }); -}); - -describe('DocViewTable at Discover Context', () => { - // here no toggleColumnButtons are rendered - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ - Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ - et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ - ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ - Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, \ - rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ - Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ - Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', - }, - }, - dataView - ); - const props = { - hit, - columns: ['extension'], - dataView, - filter: jest.fn(), - }; - - const component = mountComponent(props); - - it(`renders no toggleColumnButton`, () => { - const foundLength = findTestSubject(component, 'toggleColumnButtons').length; - expect(foundLength).toBe(0); - }); - - it(`renders addInclusiveFilterButton`, () => { - const row = findTestSubject(component, `tableDocViewRow-_index`); - const btn = findTestSubject(row, 'addInclusiveFilterButton'); - expect(btn.length).toBe(1); - btn.simulate('click'); - expect(props.filter).toBeCalled(); - }); -}); - -describe('DocViewTable at Discover Doc', () => { - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _score: 1, - _id: 'id123', - _source: { - extension: 'html', - not_mapped: 'yes', - }, - }, - dataView - ); - // here no action buttons are rendered - const props = { - hit, - dataView, - hideActionsColumn: true, - }; - const component = mountComponent(props); - const foundLength = findTestSubject(component, 'addInclusiveFilterButton').length; - - it(`renders no action buttons`, () => { - expect(foundLength).toBe(0); - }); -}); - -describe('DocViewTable at Discover Doc with Fields API', () => { - const dataViewCommerce = { - fields: { - getAll: () => [ - { - name: '_index', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'category', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'category.keyword', - displayName: 'category.keyword', - type: 'string', - scripted: false, - filterable: true, - spec: { - subType: { - multi: { - parent: 'category', - }, - }, - }, - }, - { - name: 'customer_first_name', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'customer_first_name.keyword', - displayName: 'customer_first_name.keyword', - type: 'string', - scripted: false, - filterable: false, - spec: { - subType: { - multi: { - parent: 'customer_first_name', - }, - }, - }, - }, - { - name: 'customer_first_name.nickname', - displayName: 'customer_first_name.nickname', - type: 'string', - scripted: false, - filterable: false, - spec: { - subType: { - multi: { - parent: 'customer_first_name', - }, - }, - }, - }, - { - name: 'city', - displayName: 'city', - type: 'keyword', - isMapped: true, - readFromDocValues: true, - searchable: true, - shortDotsEnable: false, - scripted: false, - filterable: false, - }, - { - name: 'city.raw', - displayName: 'city.raw', - type: 'string', - isMapped: true, - spec: { - subType: { - multi: { - parent: 'city', - }, - }, - }, - shortDotsEnable: false, - scripted: false, - filterable: false, - }, - ], - }, - metaFields: ['_index', '_type', '_score', '_id'], - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - } as unknown as DataView; - - dataViewCommerce.fields.getByName = (name: string) => { - return dataViewCommerce.fields.getAll().find((field) => field.name === name); - }; - - const fieldsHit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1.0, - fields: { - category: "Women's Clothing", - 'category.keyword': "Women's Clothing", - customer_first_name: 'Betty', - 'customer_first_name.keyword': 'Betty', - 'customer_first_name.nickname': 'Betsy', - 'city.raw': 'Los Angeles', - }, - }, - dataView - ); - const props = { - hit: fieldsHit, - columns: ['Document'], - dataView: dataViewCommerce, - filter: jest.fn(), - onAddColumn: jest.fn(), - onRemoveColumn: jest.fn(), - }; - - it('renders multifield rows if showMultiFields flag is set', () => { - const component = mountComponent(props); - - const categoryKeywordRow = findTestSubject(component, 'tableDocViewRow-category.keyword'); - expect(categoryKeywordRow.length).toBe(1); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword').length).toBe( - 1 - ); - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname').length).toBe( - 1 - ); - - expect( - findTestSubject(component, 'tableDocViewRow-category.keyword-multifieldBadge').length - ).toBe(1); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword-multifieldBadge') - .length - ).toBe(1); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname-multifieldBadge') - .length - ).toBe(1); - - expect(findTestSubject(component, 'tableDocViewRow-city.raw').length).toBe(1); - }); - - it('does not render multifield rows if showMultiFields flag is not set', () => { - const overridedServices = { - uiSettings: { - get: (key: string) => { - if (key === 'discover:showMultiFields') { - return false; - } - }, - }, - } as unknown as UnifiedDocViewerServices; - const component = mountComponent(props, overridedServices); - - const categoryKeywordRow = findTestSubject(component, 'tableDocViewRow-category.keyword'); - expect(categoryKeywordRow.length).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword').length).toBe( - 0 - ); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname').length).toBe( - 0 - ); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword-multifieldBadge') - .length - ).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name').length).toBe(1); - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname-multifieldBadge') - .length - ).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-city').length).toBe(0); - expect(findTestSubject(component, 'tableDocViewRow-city.raw').length).toBe(1); - }); -}); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx deleted file mode 100644 index e834bef5d664e..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import '../table.scss'; -import React, { useCallback, useMemo } from 'react'; -import { EuiInMemoryTable } from '@elastic/eui'; -import { getFieldIconType } from '@kbn/field-utils/src/utils/get_field_icon_type'; -import { - SHOW_MULTIFIELDS, - formatFieldValue, - getIgnoredReason, - getShouldShowFieldHandler, - isNestedFieldParent, -} from '@kbn/discover-utils'; -import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { getUnifiedDocViewerServices } from '../../../plugin'; -import { ACTIONS_COLUMN, MAIN_COLUMNS } from './table_columns'; - -export const DocViewerLegacyTable = ({ - columns, - hit, - dataView, - hideActionsColumn, - filter, - onAddColumn, - onRemoveColumn, -}: DocViewRenderProps) => { - const { fieldFormats, uiSettings } = getUnifiedDocViewerServices(); - const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS), [uiSettings]); - - const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]); - const tableColumns = useMemo(() => { - return !hideActionsColumn ? [ACTIONS_COLUMN, ...MAIN_COLUMNS] : MAIN_COLUMNS; - }, [hideActionsColumn]); - - const onToggleColumn = useMemo(() => { - if (!onRemoveColumn || !onAddColumn || !columns) { - return undefined; - } - return (field: string) => { - if (columns.includes(field)) { - onRemoveColumn(field); - } else { - onAddColumn(field); - } - }; - }, [onRemoveColumn, onAddColumn, columns]); - - const onSetRowProps = useCallback(({ field: { field } }: FieldRecordLegacy) => { - return { - key: field, - className: 'kbnDocViewer__tableRow', - 'data-test-subj': `tableDocViewRow-${field}`, - }; - }, []); - - const shouldShowFieldHandler = useMemo( - () => getShouldShowFieldHandler(Object.keys(hit.flattened), dataView, showMultiFields), - [hit.flattened, dataView, showMultiFields] - ); - - const items: FieldRecordLegacy[] = Object.keys(hit.flattened) - .filter(shouldShowFieldHandler) - .sort((fieldA, fieldB) => { - const mappingA = mapping(fieldA); - const mappingB = mapping(fieldB); - const nameA = !mappingA || !mappingA.displayName ? fieldA : mappingA.displayName; - const nameB = !mappingB || !mappingB.displayName ? fieldB : mappingB.displayName; - return nameA.localeCompare(nameB); - }) - .map((field) => { - const fieldMapping = mapping(field); - const displayName = fieldMapping?.displayName ?? field; - const fieldType = isNestedFieldParent(field, dataView) - ? 'nested' - : fieldMapping - ? getFieldIconType(fieldMapping) - : undefined; - const ignored = getIgnoredReason(fieldMapping ?? field, hit.raw._ignored); - return { - action: { - onToggleColumn, - onFilter: filter, - isActive: !!columns?.includes(field), - flattenedField: hit.flattened[field], - }, - field: { - field, - displayName, - fieldMapping, - fieldType, - scripted: Boolean(fieldMapping?.scripted), - }, - value: { - formattedValue: formatFieldValue( - hit.flattened[field], - hit.raw, - fieldFormats, - dataView, - fieldMapping - ), - ignored, - }, - }; - }); - - return ( - - ); -}; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx deleted file mode 100644 index c63c8c1ae70e9..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx +++ /dev/null @@ -1,67 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import type { DataViewField } from '@kbn/data-views-plugin/public'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { DocViewTableRowBtnFilterRemove } from './table_row_btn_filter_remove'; -import { DocViewTableRowBtnFilterExists } from './table_row_btn_filter_exists'; -import { DocViewTableRowBtnToggleColumn } from './table_row_btn_toggle_column'; -import { DocViewTableRowBtnFilterAdd } from './table_row_btn_filter_add'; - -interface TableActionsProps { - field: string; - isActive: boolean; - flattenedField: unknown; - fieldMapping?: DataViewField; - onFilter: DocViewFilterFn; - onToggleColumn: ((field: string) => void) | undefined; - ignoredValue: boolean; -} - -export const TableActions = ({ - isActive, - field, - fieldMapping, - flattenedField, - onToggleColumn, - onFilter, - ignoredValue, -}: TableActionsProps) => { - return ( -
        - {onFilter && ( - onFilter(fieldMapping, flattenedField, '+')} - /> - )} - {onFilter && ( - onFilter(fieldMapping, flattenedField, '-')} - /> - )} - {onToggleColumn && ( - onToggleColumn(field)} - /> - )} - {onFilter && ( - onFilter('_exists_', field, '+')} - scripted={fieldMapping && fieldMapping.scripted} - /> - )} -
        - ); -}; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx deleted file mode 100644 index 3b510f6130229..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx +++ /dev/null @@ -1,115 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EuiBasicTableColumn, EuiText } from '@elastic/eui'; -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { FieldName } from '@kbn/unified-doc-viewer'; -import { TableActions } from './table_cell_actions'; -import { TableFieldValue } from '../table_cell_value'; - -export const ACTIONS_COLUMN: EuiBasicTableColumn = { - field: 'action', - className: 'kbnDocViewer__tableActionsCell', - width: '108px', - mobileOptions: { header: false }, - name: ( - - - - - - ), - render: ( - { flattenedField, isActive, onFilter, onToggleColumn }: FieldRecordLegacy['action'], - { field: { field, fieldMapping }, value: { ignored } }: FieldRecordLegacy - ) => { - return ( - - ); - }, -}; -export const MAIN_COLUMNS: Array> = [ - { - field: 'field', - className: 'kbnDocViewer__tableFieldNameCell', - mobileOptions: { header: false }, - width: '30%', - name: ( - - - - - - ), - render: ({ - field, - fieldType, - displayName, - fieldMapping, - scripted, - }: FieldRecordLegacy['field']) => { - return field ? ( - - ) : ( -   - ); - }, - }, - { - field: 'value', - className: 'kbnDocViewer__tableValueCell', - mobileOptions: { header: false }, - name: ( - - - - - - ), - render: ( - { formattedValue, ignored }: FieldRecordLegacy['value'], - { field: { field }, action: { flattenedField } }: FieldRecordLegacy - ) => { - return ( - - ); - }, - }, -]; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx deleted file mode 100644 index 12e3196cac1c9..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export interface Props { - onClick: () => void; - disabled: boolean; -} - -export function DocViewTableRowBtnFilterAdd({ onClick, disabled = false }: Props) { - const tooltipContent = disabled ? ( - - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx deleted file mode 100644 index 2685b4b7b8e69..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx +++ /dev/null @@ -1,63 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export interface Props { - onClick: () => void; - disabled?: boolean; - scripted?: boolean; -} - -export function DocViewTableRowBtnFilterExists({ - onClick, - disabled = false, - scripted = false, -}: Props) { - const tooltipContent = disabled ? ( - scripted ? ( - - ) : ( - - ) - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx deleted file mode 100644 index c9073fc9831c6..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; - -export interface Props { - onClick: () => void; - disabled?: boolean; -} - -export function DocViewTableRowBtnFilterRemove({ onClick, disabled = false }: Props) { - const tooltipContent = disabled ? ( - - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx deleted file mode 100644 index 9f999248cf269..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; - -export interface Props { - active: boolean; - disabled?: boolean; - onClick: () => void; - fieldname: string; -} - -export function DocViewTableRowBtnToggleColumn({ - onClick, - active, - disabled = false, - fieldname = '', -}: Props) { - if (disabled) { - return ( - - ); - } - return ( - - } - > - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss index 64e700c73fca5..348c8c9784ad8 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss @@ -1,59 +1,3 @@ -.kbnDocViewer { - .euiTableRowCell { - vertical-align: top; - } -} - -.kbnDocViewer__tableRow { - font-size: $euiFontSizeXS; - font-family: $euiCodeFontFamily; - - // set min-width for each column except actions - .euiTableRowCell:nth-child(n+2) { - min-width: $euiSizeM * 9; - } - - .kbnDocViewer__buttons { - // Show all icons if one is focused, - &:focus-within { - .kbnDocViewer__actionButton { - opacity: 1; - } - } - } - - &:hover { - .kbnDocViewer__actionButton { - opacity: 1; - } - } - - .kbnDocViewer__actionButton { - @include euiBreakpoint('m', 'l', 'xl') { - opacity: 0; - } - - &:focus { - opacity: 1; - } - } -} - -.kbnDocViewer__tableActionsCell, -.kbnDocViewer__tableFieldNameCell { - .euiTableCellContent { - align-items: flex-start; - padding: $euiSizeXS; - } -} - -.kbnDocViewer__tableValueCell { - .euiTableCellContent { - flex-direction: column; - align-items: flex-start; - } -} - .kbnDocViewer__value { word-break: break-all; word-wrap: break-word; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx index 16976d43e58f9..632652100069d 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx @@ -497,7 +497,7 @@ export const DocViewerTable = ({ {rows.length === 0 ? ( - +

        { - if (key === TRUNCATE_MAX_HEIGHT) { - return mockTruncateMaxHeightSetting ?? TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE; - } - return; -}) as IUiSettingsClient['get']; - setUnifiedDocViewerServices(mockUnifiedDocViewerServices); let mockScrollHeight = 0; @@ -35,7 +21,6 @@ jest.spyOn(HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() = describe('TableFieldValue', () => { afterEach(() => { mockScrollHeight = 0; - mockTruncateMaxHeightSetting = undefined; }); it('should render correctly', async () => { @@ -121,97 +106,4 @@ describe('TableFieldValue', () => { expect(valueElement.getAttribute('css')).toBeNull(); expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); }); - - it('should truncate a long value in legacy table correctly', async () => { - mockScrollHeight = 1000; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - - let toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('false'); - - let valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeDefined(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(true); - - toggleButton.click(); - - toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('true'); - - valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - - toggleButton.click(); - - toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('false'); - - valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeDefined(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(true); - }); - - it('should not truncate a long value in legacy table if limit is not reached', async () => { - mockScrollHeight = 112; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - expect(screen.queryByTestId('toggleLongFieldValue-message')).toBeNull(); - - const valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - }); - - it('should not truncate a long value in legacy table if setting is 0', async () => { - mockScrollHeight = 1000; - mockTruncateMaxHeightSetting = 0; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - expect(screen.queryByTestId('toggleLongFieldValue-message')).toBeNull(); - - const valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx index 3afe935307ab2..556f671e67cbd 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx @@ -21,9 +21,7 @@ import { import classnames from 'classnames'; import React, { Fragment, useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { IgnoredReason, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; -import { FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { getUnifiedDocViewerServices } from '../../plugin'; +import { IgnoredReason } from '@kbn/discover-utils'; const DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT = 110; @@ -96,14 +94,14 @@ const IgnoreWarning: React.FC = React.memo(({ rawValue, reas ); }); -type TableFieldValueProps = Pick & { - formattedValue: FieldRecordLegacy['value']['formattedValue']; +interface TableFieldValueProps { + field: string; + formattedValue: string; rawValue: unknown; ignoreReason?: IgnoredReason; isDetails?: boolean; // true when inside EuiDataGrid cell popover - isLegacy?: boolean; // true when inside legacy table isHighlighted?: boolean; // whether it's matching a search term -}; +} export const TableFieldValue = ({ formattedValue, @@ -111,14 +109,10 @@ export const TableFieldValue = ({ rawValue, ignoreReason, isDetails, - isLegacy, isHighlighted, }: TableFieldValueProps) => { const { euiTheme } = useEuiTheme(); - const { uiSettings } = getUnifiedDocViewerServices(); - const truncationHeight = isLegacy - ? uiSettings.get(TRUNCATE_MAX_HEIGHT) - : DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT; + const truncationHeight = DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT; const [containerRef, setContainerRef] = useState(null); useResizeObserver(containerRef); diff --git a/src/plugins/unified_doc_viewer/public/plugin.tsx b/src/plugins/unified_doc_viewer/public/plugin.tsx index 41db23a52591c..4806d5fce0918 100644 --- a/src/plugins/unified_doc_viewer/public/plugin.tsx +++ b/src/plugins/unified_doc_viewer/public/plugin.tsx @@ -9,7 +9,6 @@ import React from 'react'; import type { CoreSetup, Plugin } from '@kbn/core/public'; -import { isLegacyTableEnabled } from '@kbn/discover-utils'; import { i18n } from '@kbn/i18n'; import { DocViewsRegistry } from '@kbn/unified-doc-viewer'; import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; @@ -31,9 +30,6 @@ const fallback = ( ); -const LazyDocViewerLegacyTable = dynamic(() => import('./components/doc_viewer_table/legacy'), { - fallback, -}); const LazyDocViewerTable = dynamic(() => import('./components/doc_viewer_table'), { fallback }); const LazySourceViewer = dynamic(() => import('./components/doc_viewer_source'), { fallback }); @@ -65,17 +61,7 @@ export class UnifiedDocViewerPublicPlugin }), order: 10, component: (props) => { - const { textBasedHits } = props; - const { uiSettings } = getUnifiedDocViewerServices(); - - const LazyDocView = isLegacyTableEnabled({ - uiSettings, - isEsqlMode: Array.isArray(textBasedHits), - }) - ? LazyDocViewerLegacyTable - : LazyDocViewerTable; - - return ; + return ; }, }); diff --git a/src/plugins/unified_histogram/public/container/container.tsx b/src/plugins/unified_histogram/public/container/container.tsx index 15367ae51d9b5..ce55d0773344e 100644 --- a/src/plugins/unified_histogram/public/container/container.tsx +++ b/src/plugins/unified_histogram/public/container/container.tsx @@ -28,6 +28,7 @@ import { useStateProps } from './hooks/use_state_props'; import { useStateSelector } from './utils/use_state_selector'; import { topPanelHeightSelector } from './utils/state_selectors'; import { exportVisContext } from '../utils/external_vis_context'; +import { getBreakdownField } from './utils/local_storage_utils'; type LayoutProps = Pick< UnifiedHistogramLayoutProps, @@ -50,6 +51,8 @@ export type UnifiedHistogramContainerProps = { searchSessionId?: UnifiedHistogramRequestContext['searchSessionId']; requestAdapter?: UnifiedHistogramRequestContext['adapter']; isChartLoading?: boolean; + breakdownField?: string; + onBreakdownFieldChange?: (breakdownField: string | undefined) => void; onVisContextChanged?: ( nextVisContext: UnifiedHistogramVisContext | undefined, externalVisContextStatus: UnifiedHistogramExternalVisContextStatus @@ -86,19 +89,15 @@ export type UnifiedHistogramApi = { refetch: () => void; } & Pick< UnifiedHistogramStateService, - | 'state$' - | 'setChartHidden' - | 'setTopPanelHeight' - | 'setBreakdownField' - | 'setTimeInterval' - | 'setTotalHits' + 'state$' | 'setChartHidden' | 'setTopPanelHeight' | 'setTimeInterval' | 'setTotalHits' >; export const UnifiedHistogramContainer = forwardRef< UnifiedHistogramApi, UnifiedHistogramContainerProps ->(({ onVisContextChanged, ...containerProps }, ref) => { +>(({ onBreakdownFieldChange, onVisContextChanged, ...containerProps }, ref) => { const [layoutProps, setLayoutProps] = useState(); + const [localStorageKeyPrefix, setLocalStorageKeyPrefix] = useState(); const [stateService, setStateService] = useState(); const [lensSuggestionsApi, setLensSuggestionsApi] = useState(); const [input$] = useState(() => new Subject()); @@ -114,6 +113,7 @@ export const UnifiedHistogramContainer = forwardRef< const apiHelper = await services.lens.stateHelperApi(); setLayoutProps(pick(options, 'disableAutoFetching', 'disableTriggers', 'disabledActions')); + setLocalStorageKeyPrefix(options?.localStorageKeyPrefix); setStateService(createStateService({ services, ...options })); setLensSuggestionsApi(() => apiHelper.suggestions); }); @@ -133,21 +133,34 @@ export const UnifiedHistogramContainer = forwardRef< 'state$', 'setChartHidden', 'setTopPanelHeight', - 'setBreakdownField', 'setTimeInterval', 'setTotalHits' ), }); }, [input$, stateService]); - const { dataView, query, searchSessionId, requestAdapter, isChartLoading } = containerProps; + + const { services, dataView, query, columns, searchSessionId, requestAdapter, isChartLoading } = + containerProps; const topPanelHeight = useStateSelector(stateService?.state$, topPanelHeightSelector); + const initialBreakdownField = useMemo( + () => + localStorageKeyPrefix + ? getBreakdownField(services.storage, localStorageKeyPrefix) + : undefined, + [localStorageKeyPrefix, services.storage] + ); const stateProps = useStateProps({ + services, + localStorageKeyPrefix, stateService, dataView, query, searchSessionId, requestAdapter, - columns: containerProps.columns, + columns, + breakdownField: initialBreakdownField, + ...pick(containerProps, 'breakdownField'), + onBreakdownFieldChange, }); const handleVisContextChange: UnifiedHistogramLayoutProps['onVisContextChanged'] | undefined = diff --git a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts index 7a2d36da4b1fe..f57392998d1f5 100644 --- a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts +++ b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts @@ -26,7 +26,6 @@ import { useStateProps } from './use_state_props'; describe('useStateProps', () => { const initialState: UnifiedHistogramState = { - breakdownField: 'bytes', chartHidden: false, lensRequestAdapter: new RequestAdapter(), lensAdapters: lensAdaptersMock, @@ -44,7 +43,6 @@ describe('useStateProps', () => { }); jest.spyOn(stateService, 'setChartHidden'); jest.spyOn(stateService, 'setTopPanelHeight'); - jest.spyOn(stateService, 'setBreakdownField'); jest.spyOn(stateService, 'setTimeInterval'); jest.spyOn(stateService, 'setLensRequestAdapter'); jest.spyOn(stateService, 'setTotalHits'); @@ -56,25 +54,22 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` Object { "breakdown": Object { - "field": Object { - "aggregatable": true, - "displayName": "bytes", - "filterable": true, - "name": "bytes", - "scripted": false, - "type": "number", - }, + "field": undefined, }, "chart": Object { "hidden": false, @@ -147,12 +142,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` @@ -240,12 +239,16 @@ describe('useStateProps', () => { }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index | keep field1' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current.chart).toStrictEqual({ hidden: false, timeInterval: 'auto' }); @@ -271,17 +274,20 @@ describe('useStateProps', () => { initialState: { ...initialState, currentSuggestionContext: undefined, - breakdownField, }, }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: esqlColumns, + breakdownField, + onBreakdownFieldChange: undefined, }) ); @@ -314,25 +320,30 @@ describe('useStateProps', () => { }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: esqlColumns, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); const { onBreakdownFieldChange } = result.current; act(() => { onBreakdownFieldChange({ name: breakdownField } as DataViewField); }); - expect(stateService.setBreakdownField).toHaveBeenLastCalledWith(breakdownField); }); it('should return the correct props when a rollup data view is used', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: { ...dataViewWithTimefieldMock, @@ -342,6 +353,8 @@ describe('useStateProps', () => { requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` @@ -415,12 +428,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` @@ -494,12 +511,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); @@ -553,8 +574,6 @@ describe('useStateProps', () => { act(() => { onBreakdownFieldChange({ name: 'field' } as DataViewField); }); - expect(stateService.setBreakdownField).toHaveBeenLastCalledWith('field'); - act(() => { onSuggestionContextChange({ suggestion: { title: 'Stacked Bar' }, @@ -569,12 +588,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const hook = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); (stateService.setLensRequestAdapter as jest.Mock).mockClear(); @@ -589,12 +612,16 @@ describe('useStateProps', () => { it('should clear lensRequestAdapter when chart is undefined', () => { const stateService = getStateService({ initialState }); const initialProps = { + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }; const hook = renderHook((props: Parameters[0]) => useStateProps(props), { initialProps, diff --git a/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts b/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts index 660e47f33cf0c..46244d69d1f89 100644 --- a/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts +++ b/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts @@ -17,11 +17,11 @@ import { useCallback, useEffect, useMemo } from 'react'; import { UnifiedHistogramChartLoadEvent, UnifiedHistogramFetchStatus, + UnifiedHistogramServices, UnifiedHistogramSuggestionContext, } from '../../types'; import type { UnifiedHistogramStateService } from '../services/state_service'; import { - breakdownFieldSelector, chartHiddenSelector, timeIntervalSelector, totalHitsResultSelector, @@ -30,23 +30,31 @@ import { lensDataLoadingSelector$, } from '../utils/state_selectors'; import { useStateSelector } from '../utils/use_state_selector'; +import { setBreakdownField } from '../utils/local_storage_utils'; export const useStateProps = ({ + services, + localStorageKeyPrefix, stateService, dataView, query, searchSessionId, requestAdapter, columns, + breakdownField, + onBreakdownFieldChange: originalOnBreakdownFieldChange, }: { + services: UnifiedHistogramServices; + localStorageKeyPrefix: string | undefined; stateService: UnifiedHistogramStateService | undefined; dataView: DataView; query: Query | AggregateQuery | undefined; searchSessionId: string | undefined; requestAdapter: RequestAdapter | undefined; columns: DatatableColumn[] | undefined; + breakdownField: string | undefined; + onBreakdownFieldChange: ((breakdownField: string | undefined) => void) | undefined; }) => { - const breakdownField = useStateSelector(stateService?.state$, breakdownFieldSelector); const chartHidden = useStateSelector(stateService?.state$, chartHiddenSelector); const timeInterval = useStateSelector(stateService?.state$, timeIntervalSelector); const totalHitsResult = useStateSelector(stateService?.state$, totalHitsResultSelector); @@ -166,9 +174,9 @@ export const useStateProps = ({ const onBreakdownFieldChange = useCallback( (newBreakdownField: DataViewField | undefined) => { - stateService?.setBreakdownField(newBreakdownField?.name); + originalOnBreakdownFieldChange?.(newBreakdownField?.name); }, - [stateService] + [originalOnBreakdownFieldChange] ); const onSuggestionContextChange = useCallback( @@ -182,6 +190,13 @@ export const useStateProps = ({ * Effects */ + // Sync the breakdown field with local storage + useEffect(() => { + if (localStorageKeyPrefix) { + setBreakdownField(services.storage, localStorageKeyPrefix, breakdownField); + } + }, [breakdownField, localStorageKeyPrefix, services.storage]); + // Clear the Lens request adapter when the chart is hidden useEffect(() => { if (chartHidden || !chart) { diff --git a/src/plugins/unified_histogram/public/container/services/state_service.test.ts b/src/plugins/unified_histogram/public/container/services/state_service.test.ts index 66f0549e9571f..5c3024eef7ddb 100644 --- a/src/plugins/unified_histogram/public/container/services/state_service.test.ts +++ b/src/plugins/unified_histogram/public/container/services/state_service.test.ts @@ -14,10 +14,8 @@ import { lensAdaptersMock } from '../../__mocks__/lens_adapters'; import { getChartHidden, getTopPanelHeight, - getBreakdownField, setChartHidden, setTopPanelHeight, - setBreakdownField, } from '../utils/local_storage_utils'; import { createStateService, UnifiedHistogramState } from './state_service'; @@ -27,10 +25,8 @@ jest.mock('../utils/local_storage_utils', () => { ...originalModule, getChartHidden: jest.fn(originalModule.getChartHidden), getTopPanelHeight: jest.fn(originalModule.getTopPanelHeight), - getBreakdownField: jest.fn(originalModule.getBreakdownField), setChartHidden: jest.fn(originalModule.setChartHidden), setTopPanelHeight: jest.fn(originalModule.setTopPanelHeight), - setBreakdownField: jest.fn(originalModule.setBreakdownField), }; }); @@ -38,14 +34,11 @@ describe('UnifiedHistogramStateService', () => { beforeEach(() => { (getChartHidden as jest.Mock).mockClear(); (getTopPanelHeight as jest.Mock).mockClear(); - (getBreakdownField as jest.Mock).mockClear(); (setChartHidden as jest.Mock).mockClear(); (setTopPanelHeight as jest.Mock).mockClear(); - (setBreakdownField as jest.Mock).mockClear(); }); const initialState: UnifiedHistogramState = { - breakdownField: 'bytes', chartHidden: false, lensRequestAdapter: new RequestAdapter(), lensAdapters: lensAdaptersMock, @@ -61,7 +54,6 @@ describe('UnifiedHistogramStateService', () => { let state: UnifiedHistogramState | undefined; stateService.state$.subscribe((s) => (state = s)); expect(state).toEqual({ - breakdownField: undefined, chartHidden: false, lensRequestAdapter: undefined, timeInterval: 'auto', @@ -97,10 +89,6 @@ describe('UnifiedHistogramStateService', () => { unifiedHistogramServicesMock.storage, localStorageKeyPrefix ); - expect(getBreakdownField as jest.Mock).toHaveBeenCalledWith( - unifiedHistogramServicesMock.storage, - localStorageKeyPrefix - ); }); it('should not get values from storage if localStorageKeyPrefix is not provided', () => { @@ -110,7 +98,6 @@ describe('UnifiedHistogramStateService', () => { }); expect(getChartHidden as jest.Mock).not.toHaveBeenCalled(); expect(getTopPanelHeight as jest.Mock).not.toHaveBeenCalled(); - expect(getBreakdownField as jest.Mock).not.toHaveBeenCalled(); }); it('should update state', () => { @@ -128,9 +115,6 @@ describe('UnifiedHistogramStateService', () => { stateService.setTopPanelHeight(200); newState = { ...newState, topPanelHeight: 200 }; expect(state).toEqual(newState); - stateService.setBreakdownField('test'); - newState = { ...newState, breakdownField: 'test' }; - expect(state).toEqual(newState); stateService.setTimeInterval('test'); newState = { ...newState, timeInterval: 'test' }; expect(state).toEqual(newState); @@ -166,12 +150,10 @@ describe('UnifiedHistogramStateService', () => { expect(state).toEqual(initialState); stateService.setChartHidden(true); stateService.setTopPanelHeight(200); - stateService.setBreakdownField('test'); expect(state).toEqual({ ...initialState, chartHidden: true, topPanelHeight: 200, - breakdownField: 'test', }); expect(setChartHidden as jest.Mock).toHaveBeenCalledWith( unifiedHistogramServicesMock.storage, @@ -183,11 +165,6 @@ describe('UnifiedHistogramStateService', () => { localStorageKeyPrefix, 200 ); - expect(setBreakdownField as jest.Mock).toHaveBeenCalledWith( - unifiedHistogramServicesMock.storage, - localStorageKeyPrefix, - 'test' - ); }); it('should not save state to storage if localStorageKeyPrefix is not provided', () => { @@ -200,15 +177,12 @@ describe('UnifiedHistogramStateService', () => { expect(state).toEqual(initialState); stateService.setChartHidden(true); stateService.setTopPanelHeight(200); - stateService.setBreakdownField('test'); expect(state).toEqual({ ...initialState, chartHidden: true, topPanelHeight: 200, - breakdownField: 'test', }); expect(setChartHidden as jest.Mock).not.toHaveBeenCalled(); expect(setTopPanelHeight as jest.Mock).not.toHaveBeenCalled(); - expect(setBreakdownField as jest.Mock).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/unified_histogram/public/container/services/state_service.ts b/src/plugins/unified_histogram/public/container/services/state_service.ts index c3cf82bf94578..cdca02396e3a9 100644 --- a/src/plugins/unified_histogram/public/container/services/state_service.ts +++ b/src/plugins/unified_histogram/public/container/services/state_service.ts @@ -13,10 +13,8 @@ import { PublishingSubject } from '@kbn/presentation-publishing'; import { UnifiedHistogramFetchStatus } from '../..'; import type { UnifiedHistogramServices, UnifiedHistogramChartLoadEvent } from '../../types'; import { - getBreakdownField, getChartHidden, getTopPanelHeight, - setBreakdownField, setChartHidden, setTopPanelHeight, } from '../utils/local_storage_utils'; @@ -26,10 +24,6 @@ import type { UnifiedHistogramSuggestionContext } from '../../types'; * The current state of the container */ export interface UnifiedHistogramState { - /** - * The current field used for the breakdown - */ - breakdownField: string | undefined; /** * The current Lens suggestion */ @@ -108,10 +102,6 @@ export interface UnifiedHistogramStateService { * Sets the current top panel height */ setTopPanelHeight: (topPanelHeight: number | undefined) => void; - /** - * Sets the current breakdown field - */ - setBreakdownField: (breakdownField: string | undefined) => void; /** * Sets the current time interval */ @@ -141,16 +131,13 @@ export const createStateService = ( let initialChartHidden = false; let initialTopPanelHeight: number | undefined; - let initialBreakdownField: string | undefined; if (localStorageKeyPrefix) { initialChartHidden = getChartHidden(services.storage, localStorageKeyPrefix) ?? false; initialTopPanelHeight = getTopPanelHeight(services.storage, localStorageKeyPrefix); - initialBreakdownField = getBreakdownField(services.storage, localStorageKeyPrefix); } const state$ = new BehaviorSubject({ - breakdownField: initialBreakdownField, chartHidden: initialChartHidden, currentSuggestionContext: undefined, lensRequestAdapter: undefined, @@ -187,14 +174,6 @@ export const createStateService = ( updateState({ topPanelHeight }); }, - setBreakdownField: (breakdownField: string | undefined) => { - if (localStorageKeyPrefix) { - setBreakdownField(services.storage, localStorageKeyPrefix, breakdownField); - } - - updateState({ breakdownField }); - }, - setCurrentSuggestionContext: ( suggestionContext: UnifiedHistogramSuggestionContext | undefined ) => { diff --git a/src/plugins/unified_histogram/public/container/utils/state_selectors.ts b/src/plugins/unified_histogram/public/container/utils/state_selectors.ts index 9274c4fabd301..c20ec4193c53c 100644 --- a/src/plugins/unified_histogram/public/container/utils/state_selectors.ts +++ b/src/plugins/unified_histogram/public/container/utils/state_selectors.ts @@ -9,7 +9,6 @@ import type { UnifiedHistogramState } from '../services/state_service'; -export const breakdownFieldSelector = (state: UnifiedHistogramState) => state.breakdownField; export const chartHiddenSelector = (state: UnifiedHistogramState) => state.chartHidden; export const timeIntervalSelector = (state: UnifiedHistogramState) => state.timeInterval; export const topPanelHeightSelector = (state: UnifiedHistogramState) => state.topPanelHeight; diff --git a/src/plugins/unified_histogram/public/mocks.ts b/src/plugins/unified_histogram/public/mocks.ts index 4772739e28361..11ebd50239257 100644 --- a/src/plugins/unified_histogram/public/mocks.ts +++ b/src/plugins/unified_histogram/public/mocks.ts @@ -15,7 +15,6 @@ export const createMockUnifiedHistogramApi = () => { state$: new Observable(), setChartHidden: jest.fn(), setTopPanelHeight: jest.fn(), - setBreakdownField: jest.fn(), setTimeInterval: jest.fn(), setTotalHits: jest.fn(), refetch: jest.fn(), diff --git a/src/plugins/unified_histogram/public/services/lens_vis_service.ts b/src/plugins/unified_histogram/public/services/lens_vis_service.ts index 5342ef4723b13..52968693ed650 100644 --- a/src/plugins/unified_histogram/public/services/lens_vis_service.ts +++ b/src/plugins/unified_histogram/public/services/lens_vis_service.ts @@ -329,8 +329,13 @@ export class LensVisService { queryParams: QueryParams; timeInterval: string | undefined; breakdownField: DataViewField | undefined; - }): Suggestion => { + }): Suggestion | undefined => { const { dataView } = queryParams; + + if (!dataView.isTimeBased() || !dataView.timeFieldName) { + return undefined; + } + const showBreakdown = breakdownField && fieldSupportsBreakdown(breakdownField); let columnOrder = ['date_column', 'count_column']; @@ -343,7 +348,7 @@ export class LensVisService { date_column: { dataType: 'date', isBucketed: true, - label: dataView.timeFieldName ?? '', + label: dataView.timeFieldName, operationType: 'date_histogram', scale: 'interval', sourceField: dataView.timeFieldName, diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx index cc602efa61422..425624c3e194d 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx @@ -280,7 +280,7 @@ class FilterEditorComponent extends Component { diff --git a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx index 19ba668092466..9c8e7b074149f 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx @@ -388,7 +388,7 @@ function FilterItemComponent(props: FilterItemProps) { ) : ( +

        ); diff --git a/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx b/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx index 319d3b0f49846..16ef016ff4006 100644 --- a/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx +++ b/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx @@ -105,7 +105,7 @@ export const FilterEditorWrapper = React.memo(function FilterEditorWrapper({ } return ( -
        +
        {newFilter && ( -

        {strings.getNoDataPopoverContent()}

        +

        {strings.getNoDataPopoverContent()}

        } minWidth={300} 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 4d4db4438d74d..037997bbd5c86 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 @@ -628,7 +628,7 @@ export const QueryBarTopRow = React.memo( function renderDataViewsPicker() { if (props.dataViewPickerComponentProps && !Boolean(isQueryLangSelected)) { return ( - + {!isQueryLangSelected ? renderQueryInput() : null} diff --git a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx index 2e3b0fab0a161..2e76341ae6071 100644 --- a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx @@ -808,7 +808,7 @@ export default class QueryStringInputUI extends PureComponent
        -
        +

        - + {props.children} diff --git a/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js index f30dfce37e5c6..7a93aa271b5d5 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js @@ -122,7 +122,7 @@ export class Percentiles extends Component { {/* If the series is grouped by, then these colors are not respected, no need to display the color picker */} {!isGroupedBy && !['table', 'metric', 'markdown'].includes(panel.type) && ( - + -

        +
        {i18n.translate('visTypeTimeseries.indexPatternSelect.switchModePopover.title', { defaultMessage: 'Data view mode', diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap index 7ded8e2254aa9..18ce44a9fb7ec 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap @@ -18,7 +18,7 @@ exports[`src/legacy/core_plugins/metrics/public/visualizations/views/timeseries/ "radius": 1, "stroke": "rgb(0, 156, 224)", "strokeWidth": 5, - "visible": false, + "visible": "never", }, } } diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap index 054ca0f0d8193..28bfd0c698307 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap @@ -17,7 +17,7 @@ Object { "radius": 1, "stroke": "rgb(224, 0, 221)", "strokeWidth": 1, - "visible": true, + "visible": "always", }, }, "curve": 7, @@ -41,7 +41,7 @@ Object { "radius": 0.5, "stroke": "#000", "strokeWidth": 5, - "visible": false, + "visible": "never", }, }, "curve": 9, diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js index 0da1e8e474b50..6bfbbb7bfb287 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js @@ -27,7 +27,7 @@ export const getAreaStyles = ({ points, lines, color }) => ({ radius: points.radius || 0.5, stroke: color || DEFAULT_COLOR, strokeWidth: points.lineWidth || 5, - visible: points.lineWidth > 0 && Boolean(points.show), + visible: points.lineWidth > 0 && Boolean(points.show) ? 'always' : 'never', }, }, curve: lines.steps ? CurveType.CURVE_STEP_AFTER : CurveType.LINEAR, diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts index 51150cd658733..450238142b236 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts @@ -53,7 +53,7 @@ export const vegaVisTooltipStyles = (euiThemeContext: UseEuiTheme) => { 'max-width', mathWithUnits(euiTheme.size.base, (x) => x * 10) )} - color: ${euiTheme.colors.mediumShade}; + color: ${euiTheme.colors.lightShade}; ${logicalTextAlignCSS('right')} ${logicalCSS('padding-right', euiTheme.size.xs)} } diff --git a/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx b/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx index d4124ca216d04..e0be21c3272e4 100644 --- a/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx +++ b/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx @@ -49,7 +49,7 @@ export const VisualizationMissedSavedObjectError = ({ path: '/kibana/indexPatterns/create', })} data-test-subj="configuration-failure-reconfigure-indexpatterns" - style={{ width: '100%' }} + css={{ width: '100%' }} > {i18n.translate('visualizations.missedDataView.dataViewReconfigure', { defaultMessage: `Recreate it in the data view management page`, diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 4993c0168313a..71338e96ea145 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -472,7 +472,7 @@ export const getVisualizeEmbeddableFactory: (deps: { return (
        {/* Replicate the loading state for the expression renderer to avoid FOUC */} - + {isLoading && } {!isLoading && error && ( { + await PageObjects.console.enterText(`POST _ingest/pipeline/_simulate +{ + "pipeline": { + "processors": [ + { + "script": {`); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + await PageObjects.console.enterText(`"`); + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + + // Iterate on the first 10 suggestions (the ones that are only visible without scrolling) + const suggestions = []; + for (let i = 0; i < 10; i++) { + suggestions.push(await PageObjects.console.getAutocompleteSuggestion(i)); + } + + // and expect the array to not have duplicates + expect(suggestions).to.eql(_.uniq(suggestions)); + }); + describe('Autocomplete behavior', () => { beforeEach(async () => { await PageObjects.console.clearEditorText(); @@ -377,5 +399,41 @@ GET _search expect(await PageObjects.console.getAutocompleteSuggestion(1)).to.be.eql(undefined); }); }); + + describe('Autocomplete shouldnt trigger within', () => { + beforeEach(async () => { + await PageObjects.console.skipTourIfExists(); + await PageObjects.console.clearEditorText(); + }); + + it('a hash comment', async () => { + await PageObjects.console.enterText(`# GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a simple double slash comment', async () => { + await PageObjects.console.enterText(`// GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a single line block comment', async () => { + await PageObjects.console.enterText(`/* GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a multiline block comment', async () => { + await PageObjects.console.enterText(`/* + GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + }); }); } diff --git a/test/functional/apps/console/_context_menu.ts b/test/functional/apps/console/_context_menu.ts index 4ee3c2cca40a7..0e126467c04c2 100644 --- a/test/functional/apps/console/_context_menu.ts +++ b/test/functional/apps/console/_context_menu.ts @@ -70,6 +70,55 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { } }); + it('doesnt allow to copy kbn requests as anything other than curl', async () => { + const canReadClipboard = await browser.checkBrowserPermission('clipboard-read'); + + await PageObjects.console.clearEditorText(); + await PageObjects.console.enterText('GET _search\n'); + + // Add a kbn request + // pressEnter + await PageObjects.console.enterText('GET kbn:/api/spaces/space'); + // Make sure to select the es and kbn request + await PageObjects.console.selectAllRequests(); + + await PageObjects.console.clickContextMenu(); + await PageObjects.console.clickCopyAsButton(); + + let resultToast = await toasts.getElementByIndex(1); + let toastText = await resultToast.getVisibleText(); + + expect(toastText).to.be('Requests copied to clipboard as curl'); + + // Check if the clipboard has the curl request + if (canReadClipboard) { + const clipboardText = await browser.getClipboardValue(); + expect(clipboardText).to.contain('curl -X GET'); + } + + // Wait until async operation is done + await PageObjects.common.sleep(1000); + + // Focus editor once again + await PageObjects.console.focusInputEditor(); + + // Try to copy as javascript + await PageObjects.console.clickContextMenu(); + await PageObjects.console.changeLanguageAndCopy('javascript'); + + resultToast = await toasts.getElementByIndex(2); + toastText = await resultToast.getVisibleText(); + + expect(toastText).to.be('Kibana requests can only be copied as curl'); + + // Since we tried to copy as javascript, the clipboard should still have + // the curl request + if (canReadClipboard) { + const clipboardText = await browser.getClipboardValue(); + expect(clipboardText).to.contain('curl -X GET'); + } + }); + it.skip('allows to change default language', async () => { await PageObjects.console.clickContextMenu(); diff --git a/test/functional/apps/context/classic/_discover_navigation.ts b/test/functional/apps/context/classic/_discover_navigation.ts deleted file mode 100644 index 476a4bfac9e18..0000000000000 --- a/test/functional/apps/context/classic/_discover_navigation.ts +++ /dev/null @@ -1,168 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const TEST_COLUMN_NAMES = ['@message']; -const TEST_FILTER_COLUMN_NAMES = [ - ['extension', 'jpg', 'extension.raw'], - ['geo.src', 'IN', 'geo.src'], -]; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const { common, discover, timePicker, dashboard, context, header, unifiedFieldList } = - getPageObjects([ - 'common', - 'discover', - 'timePicker', - 'dashboard', - 'context', - 'header', - 'unifiedFieldList', - ]); - const testSubjects = getService('testSubjects'); - const dashboardAddPanel = getService('dashboardAddPanel'); - const browser = getService('browser'); - const kibanaServer = getService('kibanaServer'); - - describe('context link in discover classic', () => { - before(async () => { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, - defaultIndex: 'logstash-*', - }); - await common.navigateToApp('discover'); - await header.waitUntilLoadingHasFinished(); - for (const columnName of TEST_COLUMN_NAMES) { - await unifiedFieldList.clickFieldListItemAdd(columnName); - } - - for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { - await unifiedFieldList.clickFieldListItem(columnName); - await unifiedFieldList.clickFieldListPlusFilter(columnName, value); - } - }); - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should open the context view with the same columns', async () => { - const columnNames = await docTable.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - - it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { - /** - * Helper function to get the first timestamp of the document table - * @param isAnchorRow - determins if just the anchor row of context should be selected - */ - const getTimestamp = async (isAnchorRow: boolean = false) => { - const contextFields = await docTable.getFields({ isAnchorRow }); - return contextFields[0][0]; - }; - // get the timestamp of the first row - - const firstDiscoverTimestamp = await getTimestamp(); - - // check the anchor timestamp in the context view - await retry.waitFor('selected document timestamp matches anchor timestamp ', async () => { - // navigate to the context view - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[0].click(); - await context.waitUntilContextLoadingHasFinished(); - const anchorTimestamp = await getTimestamp(true); - return anchorTimestamp === firstDiscoverTimestamp; - }); - - await retry.waitFor('next anchor timestamp matches previous anchor timestamp', async () => { - // get the timestamp of the first row - const firstContextTimestamp = await getTimestamp(false); - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[0].click(); - await context.waitUntilContextLoadingHasFinished(); - const anchorTimestamp = await getTimestamp(true); - return anchorTimestamp === firstContextTimestamp; - }); - }); - - it('should open the context view with the filters disabled', async () => { - let disabledFilterCounter = 0; - for (const [_, value, columnId] of TEST_FILTER_COLUMN_NAMES) { - if (await filterBar.hasFilter(columnId, value, false)) { - disabledFilterCounter++; - } - } - expect(disabledFilterCounter).to.be(TEST_FILTER_COLUMN_NAMES.length); - }); - - // bugfix: https://github.com/elastic/kibana/issues/92099 - it('should navigate to the first document and then back to discover', async () => { - await context.waitUntilContextLoadingHasFinished(); - - // navigate to the doc view - await docTable.clickRowToggle({ rowIndex: 0 }); - - // click the open action - await retry.try(async () => { - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - if (!rowActions.length) { - throw new Error('row actions empty, trying again'); - } - await rowActions[1].click(); - }); - - const hasDocHit = await testSubjects.exists('doc-hit'); - expect(hasDocHit).to.be(true); - - await testSubjects.click('~breadcrumb & ~first'); - await discover.waitForDiscoverAppOnScreen(); - await discover.waitForDocTableLoadingComplete(); - }); - - it('navigates to doc view from embeddable', async () => { - await common.navigateToApp('discover'); - await discover.saveSearch('my classic search'); - await header.waitUntilLoadingHasFinished(); - - await dashboard.navigateToApp(); - await dashboard.gotoDashboardLandingPage(); - await dashboard.clickNewDashboard(); - - await dashboardAddPanel.addSavedSearch('my classic search'); - await header.waitUntilLoadingHasFinished(); - - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[1].click(); - await common.sleep(250); - - // close popup - const alert = await browser.getAlert(); - await alert?.accept(); - if (await testSubjects.exists('confirmModalConfirmButton')) { - await testSubjects.click('confirmModalConfirmButton'); - } - - await retry.waitFor('navigate to doc view', async () => { - const currentUrl = await browser.getCurrentUrl(); - return currentUrl.includes('#/doc'); - }); - await retry.waitFor('doc view being rendered', async () => { - return await discover.isShowingDocViewer(); - }); - }); - }); -} diff --git a/test/functional/apps/context/classic/_filters.ts b/test/functional/apps/context/classic/_filters.ts deleted file mode 100644 index fd2ce16982f31..0000000000000 --- a/test/functional/apps/context/classic/_filters.ts +++ /dev/null @@ -1,69 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const TEST_INDEX_PATTERN = 'logstash-*'; -const TEST_ANCHOR_ID = 'AU_x3_BrGFA8no6QjjaI'; -const TEST_ANCHOR_FILTER_FIELD = 'geo.src'; -const TEST_ANCHOR_FILTER_VALUE = 'IN'; -const TEST_COLUMN_NAMES = ['extension', 'geo.src']; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - - const PageObjects = getPageObjects(['common', 'context']); - - describe('context filters', function contextSize() { - before(async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - beforeEach(async function () { - await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID, { - columns: TEST_COLUMN_NAMES, - }); - }); - - it('inclusive filter should be addable via expanded doc table rows', async function () { - await retry.waitFor(`filter ${TEST_ANCHOR_FILTER_FIELD} in filterbar`, async () => { - await docTable.toggleRowExpanded({ isAnchorRow: true }); - const anchorDetailsRow = await docTable.getAnchorDetailsRow(); - await docTable.addInclusiveFilter(anchorDetailsRow, TEST_ANCHOR_FILTER_FIELD); - await PageObjects.context.waitUntilContextLoadingHasFinished(); - - return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, true); - }); - await retry.waitFor(`filter matching docs in docTable`, async () => { - const fields = await docTable.getFields(); - return fields - .map((row) => row[2]) - .every((fieldContent) => fieldContent === TEST_ANCHOR_FILTER_VALUE); - }); - }); - - it('filter for presence should be addable via expanded doc table rows', async function () { - await docTable.toggleRowExpanded({ isAnchorRow: true }); - - await retry.waitFor('an exists filter in the filterbar', async () => { - const anchorDetailsRow = await docTable.getAnchorDetailsRow(); - await docTable.addExistsFilter(anchorDetailsRow, TEST_ANCHOR_FILTER_FIELD); - await PageObjects.context.waitUntilContextLoadingHasFinished(); - return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, 'exists', true); - }); - }); - }); -} diff --git a/test/functional/apps/context/index.ts b/test/functional/apps/context/index.ts index 2cfc8cf855a2d..5cccbf163a8fb 100644 --- a/test/functional/apps/context/index.ts +++ b/test/functional/apps/context/index.ts @@ -33,9 +33,7 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_context_accessibility')); loadTestFile(require.resolve('./_context_navigation')); loadTestFile(require.resolve('./_discover_navigation')); - loadTestFile(require.resolve('./classic/_discover_navigation')); loadTestFile(require.resolve('./_filters')); - loadTestFile(require.resolve('./classic/_filters')); loadTestFile(require.resolve('./_size')); loadTestFile(require.resolve('./_date_nanos')); loadTestFile(require.resolve('./_date_nanos_custom_timestamp')); diff --git a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts index 07eb00d5817be..014d1dd15ed4f 100644 --- a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts +++ b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts @@ -30,7 +30,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await kibanaServer.uiSettings.replace({ defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', - 'doc_table:legacy': false, }); await dashboard.navigateToApp(); await filterBar.ensureFieldEditorModalIsClosed(); diff --git a/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts b/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts index e1935a0839966..c80ee8e844cfa 100644 --- a/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts +++ b/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts @@ -23,12 +23,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const queryBar = getService('queryBar'); const security = getService('security'); - const { dashboard, discover, header, timePicker } = getPageObjects([ - 'dashboard', - 'discover', - 'header', - 'timePicker', - ]); + const { dashboard, header, timePicker } = getPageObjects(['dashboard', 'header', 'timePicker']); describe('dashboard filter bar', () => { before(async () => { @@ -201,12 +196,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('are added when a cell magnifying glass is clicked', async function () { await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); await dashboard.waitForRenderComplete(); - const isLegacyDefault = await discover.useLegacyTable(); - if (isLegacyDefault) { - await testSubjects.click('docTableCellFilter'); - } else { - await dataGrid.clickCellFilterForButtonExcludingControlColumns(1, 1); - } + await dataGrid.clickCellFilterForButtonExcludingControlColumns(1, 1); const filterCount = await filterBar.getFilterCount(); expect(filterCount).to.equal(1); }); diff --git a/test/functional/apps/dashboard/group3/dashboard_time_picker.ts b/test/functional/apps/dashboard/group3/dashboard_time_picker.ts index 2e5d4217909f0..a1fb468a9dd28 100644 --- a/test/functional/apps/dashboard/group3/dashboard_time_picker.ts +++ b/test/functional/apps/dashboard/group3/dashboard_time_picker.ts @@ -13,16 +13,10 @@ import { PIE_CHART_VIS_NAME } from '../../../page_objects/dashboard_page'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const dashboardExpect = getService('dashboardExpect'); const pieChart = getService('pieChart'); const elasticChart = getService('elasticChart'); const dashboardVisualizations = getService('dashboardVisualizations'); - const { dashboard, header, timePicker, discover } = getPageObjects([ - 'dashboard', - 'header', - 'timePicker', - 'discover', - ]); + const { dashboard, header, timePicker } = getPageObjects(['dashboard', 'header', 'timePicker']); const browser = getService('browser'); const log = getService('log'); const kibanaServer = getService('kibanaServer'); @@ -59,28 +53,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { fields: ['bytes', 'agent'], }); - const isLegacyDefault = await discover.useLegacyTable(); - if (isLegacyDefault) { - await dashboardExpect.docTableFieldCount(150); + const docCount = await dataGrid.getDocCount(); + expect(docCount).to.above(10); - // Set to time range with no data - await timePicker.setAbsoluteRange( - 'Jan 1, 2000 @ 00:00:00.000', - 'Jan 1, 2000 @ 01:00:00.000' - ); - await dashboardExpect.docTableFieldCount(0); - } else { - const docCount = await dataGrid.getDocCount(); - expect(docCount).to.above(10); - - // Set to time range with no data - await timePicker.setAbsoluteRange( - 'Jan 1, 2000 @ 00:00:00.000', - 'Jan 1, 2000 @ 01:00:00.000' - ); - const noResults = await dataGrid.hasNoResults(); - expect(noResults).to.be.ok(); - } + // Set to time range with no data + await timePicker.setAbsoluteRange('Jan 1, 2000 @ 00:00:00.000', 'Jan 1, 2000 @ 01:00:00.000'); + const noResults = await dataGrid.hasNoResults(); + expect(noResults).to.be.ok(); }); it('Timepicker start, end, interval values are set by url', async () => { diff --git a/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts b/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts deleted file mode 100644 index c56ecc020f2bf..0000000000000 --- a/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts +++ /dev/null @@ -1,75 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const testSubjects = getService('testSubjects'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const esArchiver = getService('esArchiver'); - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - - describe('classic table doc link', function contextSize() { - before(async () => { - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - 'discover:searchFieldsFromSource': true, - }); - }); - after(async () => { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - }); - - beforeEach(async function () { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - await discover.waitForDocTableLoadingComplete(); - }); - - it('should open the doc view of the selected document', async function () { - // navigate to the doc view - await docTable.clickRowToggle({ rowIndex: 0 }); - - // click the open action - await retry.try(async () => { - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - if (!rowActions.length) { - throw new Error('row actions empty, trying again'); - } - await rowActions[1].click(); - }); - - await retry.waitFor('hit loaded', async () => { - const hasDocHit = await testSubjects.exists('doc-hit'); - return !!hasDocHit; - }); - }); - - it('should create an exists filter from the doc view of the selected document', async function () { - await discover.waitUntilSearchingHasFinished(); - - await docTable.toggleRowExpanded(); - const detailsRow = await docTable.getDetailsRow(); - await docTable.addExistsFilter(detailsRow, '@timestamp'); - - const hasExistsFilter = await filterBar.hasFilter('@timestamp', 'exists', true, false, false); - expect(hasExistsFilter).to.be(true); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_discover_fields_api.ts b/test/functional/apps/discover/classic/_discover_fields_api.ts deleted file mode 100644 index e0fe867a25c8b..0000000000000 --- a/test/functional/apps/discover/classic/_discover_fields_api.ts +++ /dev/null @@ -1,98 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, discover, timePicker, settings, unifiedFieldList } = getPageObjects([ - 'common', - 'discover', - 'timePicker', - 'settings', - 'unifiedFieldList', - ]); - const defaultSettings = { - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': false, - 'doc_table:legacy': true, - }; - describe('discover uses fields API test', function describeIndexTests() { - before(async function () { - log.debug('load kibana index with default index pattern'); - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should correctly display documents', async function () { - log.debug('check if Document title exists in the grid'); - expect(await discover.getDocHeader()).to.have.string('Document'); - const rowData = await discover.getDocTableIndex(1); - log.debug('check the newest doc timestamp in UTC (check diff timezone in last test)'); - expect(rowData.startsWith('Sep 22, 2015 @ 23:50:13.253')).to.be.ok(); - const expectedHitCount = '14,004'; - await retry.try(async function () { - expect(await discover.getHitCount()).to.be(expectedHitCount); - }); - }); - - it('adding a column removes a default column', async function () { - await unifiedFieldList.clickFieldListItemAdd('_score'); - expect(await discover.getDocHeader()).to.have.string('_score'); - expect(await discover.getDocHeader()).not.to.have.string('Document'); - }); - - it('removing a column adds a default column', async function () { - await unifiedFieldList.clickFieldListItemRemove('_score'); - expect(await discover.getDocHeader()).not.to.have.string('_score'); - expect(await discover.getDocHeader()).to.have.string('Document'); - }); - - it('displays _source viewer in doc viewer', async function () { - await discover.clickDocTableRowToggle(0); - await discover.isShowingDocViewer(); - await discover.clickDocViewerTab('doc_view_source'); - await discover.expectSourceViewerToExist(); - }); - - it('switches to _source column when fields API is no longer used', async function () { - await settings.navigateTo(); - await settings.clickKibanaSettings(); - await settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); - - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - - expect(await discover.getDocHeader()).to.have.string('_source'); - }); - - it('switches to Document column when fields API is used', async function () { - await settings.navigateTo(); - await settings.clickKibanaSettings(); - await settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); - - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - - expect(await discover.getDocHeader()).to.have.string('Document'); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_doc_table.ts b/test/functional/apps/discover/classic/_doc_table.ts deleted file mode 100644 index 5c765a6b2ef21..0000000000000 --- a/test/functional/apps/discover/classic/_doc_table.ts +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const browser = getService('browser'); - const log = getService('log'); - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const docTable = getService('docTable'); - const queryBar = getService('queryBar'); - const find = getService('find'); - const { common, discover, header, timePicker, unifiedFieldList } = getPageObjects([ - 'common', - 'discover', - 'header', - 'timePicker', - 'unifiedFieldList', - ]); - const defaultSettings = { - defaultIndex: 'logstash-*', - hideAnnouncements: true, - 'doc_table:legacy': true, - }; - const testSubjects = getService('testSubjects'); - - describe('discover doc table', function describeIndexTests() { - const rowsHardLimit = 500; - - before(async function () { - log.debug('load kibana index with default index pattern'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - - // and load a set of makelogs data - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - log.debug('discover doc table'); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover.json'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.uiSettings.replace({}); - }); - - it('should show records by default', async function () { - // with the default range the number of hits is ~14000 - const rows = await discover.getDocTableRows(); - expect(rows.length).to.be.greaterThan(0); - }); - - it('should refresh the table content when changing time window', async function () { - const initialRows = await discover.getDocTableRows(); - - const fromTime = 'Sep 20, 2015 @ 23:00:00.000'; - const toTime = 'Sep 20, 2015 @ 23:14:00.000'; - - await timePicker.setAbsoluteRange(fromTime, toTime); - await discover.waitUntilSearchingHasFinished(); - - const finalRows = await discover.getDocTableRows(); - expect(finalRows.length).to.be.below(initialRows.length); - await timePicker.setDefaultAbsoluteRange(); - }); - - describe('classic table in window 900x700', function () { - before(async () => { - await browser.setWindowSize(900, 700); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should load more rows when scrolling down the document table', async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - await testSubjects.scrollIntoView('discoverBackToTop'); - // now count the rows - await retry.waitFor('next batch of documents to be displayed', async () => { - const actual = await testSubjects.findAll('docTableRow'); - log.debug(`initial doc nr: ${initialRows.length}, actual doc nr: ${actual.length}`); - return actual.length > initialRows.length; - }); - }); - }); - - describe('classic table in window 600x700', function () { - before(async () => { - await browser.setWindowSize(600, 700); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should load more rows when scrolling down the document table', async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - await testSubjects.scrollIntoView('discoverBackToTop'); - // now count the rows - await retry.waitFor('next batch of documents to be displayed', async () => { - const actual = await testSubjects.findAll('docTableRow'); - log.debug(`initial doc nr: ${initialRows.length}, actual doc nr: ${actual.length}`); - return actual.length > initialRows.length; - }); - }); - }); - - describe('legacy', function () { - before(async () => { - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - it(`should load up to ${rowsHardLimit} rows when scrolling at the end of the table`, async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - // click the Skip to the end of the table - await discover.skipToEndOfDocTable(); - // now count the rows - const finalRows = await testSubjects.findAll('docTableRow'); - expect(finalRows.length).to.be.above(initialRows.length); - expect(finalRows.length).to.be(rowsHardLimit); - await discover.backToTop(); - }); - - it('should go the end and back to top of the classic table when using the accessible buttons', async function () { - // click the Skip to the end of the table - await discover.skipToEndOfDocTable(); - // now check the footer text content - const footer = await discover.getDocTableFooter(); - expect(await footer.getVisibleText()).to.have.string(rowsHardLimit); - await discover.backToTop(); - // check that the skip to end of the table button now has focus - const skipButton = await testSubjects.find('discoverSkipTableButton'); - const activeElement = await find.activeElement(); - const activeElementText = await activeElement.getVisibleText(); - const skipButtonText = await skipButton.getVisibleText(); - expect(skipButtonText === activeElementText).to.be(true); - }); - - describe('expand a document row', function () { - const rowToInspect = 1; - beforeEach(async function () { - // close the toggle if open - const details = await docTable.getDetailsRows(); - if (details.length) { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - } - }); - - it('should expand the detail row when the toggle arrow is clicked', async function () { - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - const detailsEl = await docTable.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - expect(defaultMessageEl).to.be.ok(); - }); - }); - - it('should show the detail panel actions', async function () { - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - // const detailsEl = await discover.getDocTableRowDetails(rowToInspect); - const [surroundingActionEl, singleActionEl] = await docTable.getRowActions({ - isAnchorRow: false, - rowIndex: rowToInspect - 1, - }); - expect(surroundingActionEl).to.be.ok(); - expect(singleActionEl).to.be.ok(); - // TODO: test something more meaninful here? - }); - }); - - it('should not close the detail panel actions when data is re-requested', async function () { - await retry.try(async function () { - const nrOfFetches = await discover.getNrOfFetches(); - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - const detailsEl = await docTable.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - expect(defaultMessageEl).to.be.ok(); - await queryBar.submitQuery(); - const nrOfFetchesResubmit = await discover.getNrOfFetches(); - expect(nrOfFetchesResubmit).to.be.above(nrOfFetches); - const defaultMessageElResubmit = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - - expect(defaultMessageElResubmit).to.be.ok(); - }); - }); - - it('should show allow toggling columns from the expanded document', async function () { - await discover.clickNewSearchButton(); - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - - // add columns - const fields = ['_id', '_index', 'agent']; - for (const field of fields) { - await testSubjects.click(`toggleColumnButton-${field}`); - await testSubjects.click(`tableDocViewRow-${field}`); // to suppress the appeared tooltip - } - - const headerWithFields = await docTable.getHeaderFields(); - expect(headerWithFields.join(' ')).to.contain(fields.join(' ')); - - // remove columns - for (const field of fields) { - await testSubjects.click(`toggleColumnButton-${field}`); - await testSubjects.click(`tableDocViewRow-${field}`); - } - - const headerWithoutFields = await docTable.getHeaderFields(); - expect(headerWithoutFields.join(' ')).not.to.contain(fields.join(' ')); - }); - }); - }); - - describe('add and remove columns', function () { - const extraColumns = ['phpmemory', 'ip']; - const expectedFieldLength: Record = { - phpmemory: 1, - ip: 4, - }; - afterEach(async function () { - for (const column of extraColumns) { - await unifiedFieldList.clickFieldListItemRemove(column); - await header.waitUntilLoadingHasFinished(); - } - }); - - it('should add more columns to the table', async function () { - for (const column of extraColumns) { - await unifiedFieldList.clearFieldSearchInput(); - await unifiedFieldList.findFieldByName(column); - await unifiedFieldList.waitUntilFieldlistHasCountOfFields(expectedFieldLength[column]); - await retry.waitFor('field to appear', async function () { - return await testSubjects.exists(`field-${column}`); - }); - await unifiedFieldList.clickFieldListItemAdd(column); - await header.waitUntilLoadingHasFinished(); - // test the header now - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - const docHeaderText = await docHeader.getVisibleText(); - expect(docHeaderText).to.have.string(column); - } - }); - - it('should remove columns from the table', async function () { - for (const column of extraColumns) { - await unifiedFieldList.clearFieldSearchInput(); - await unifiedFieldList.findFieldByName(column); - await unifiedFieldList.waitUntilFieldlistHasCountOfFields(expectedFieldLength[column]); - await unifiedFieldList.clickFieldListItemAdd(column); - await header.waitUntilLoadingHasFinished(); - } - // remove the second column - await unifiedFieldList.clickFieldListItemRemove(extraColumns[1]); - await header.waitUntilLoadingHasFinished(); - // test that the second column is no longer there - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - expect(await docHeader.getVisibleText()).to.not.have.string(extraColumns[1]); - }); - }); - - it('should make the document table scrollable', async function () { - await unifiedFieldList.clearFieldSearchInput(); - const dscTableWrapper = await find.byCssSelector('.kbnDocTableWrapper'); - const fieldNames = await unifiedFieldList.getAllFieldNames(); - const clientHeight = await dscTableWrapper.getAttribute('clientHeight'); - let fieldCounter = 0; - const checkScrollable = async () => { - const scrollWidth = await dscTableWrapper.getAttribute('scrollWidth'); - const clientWidth = await dscTableWrapper.getAttribute('clientWidth'); - log.debug(`scrollWidth: ${scrollWidth}, clientWidth: ${clientWidth}`); - return Number(scrollWidth) > Number(clientWidth); - }; - const addColumn = async () => { - await unifiedFieldList.clickFieldListItemAdd(fieldNames[fieldCounter++]); - }; - - await addColumn(); - const isScrollable = await checkScrollable(); - expect(isScrollable).to.be(false); - - await retry.waitForWithTimeout('container to be scrollable', 60 * 1000, async () => { - await addColumn(); - return await checkScrollable(); - }); - // so now we need to check if the horizontal scrollbar is displayed - const newClientHeight = await dscTableWrapper.getAttribute('clientHeight'); - expect(Number(clientHeight)).to.be.above(Number(newClientHeight)); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_doc_table_newline.ts b/test/functional/apps/discover/classic/_doc_table_newline.ts deleted file mode 100644 index 3c2b426a2dbe4..0000000000000 --- a/test/functional/apps/discover/classic/_doc_table_newline.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, unifiedFieldList } = getPageObjects(['common', 'unifiedFieldList']); - const find = getService('find'); - const log = getService('log'); - const retry = getService('retry'); - const security = getService('security'); - - describe('discover doc table newline handling', function describeIndexTests() { - before(async function () { - await security.testUser.setRoles(['kibana_admin', 'kibana_message_with_newline']); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/message_with_newline'); - await kibanaServer.importExport.load( - 'test/functional/fixtures/kbn_archiver/message_with_newline.json' - ); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'newline-test', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - }); - - after(async () => { - await security.testUser.restoreDefaults(); - await esArchiver.unload('test/functional/fixtures/es_archiver/message_with_newline'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.uiSettings.replace({}); - }); - - it('should break text on newlines', async function () { - await unifiedFieldList.clickFieldListItemToggle('message'); - const dscTableRows = await find.allByCssSelector('.kbnDocTable__row'); - - await retry.waitFor('height of multi-line content > single-line content', async () => { - const heightWithoutNewline = await dscTableRows[0].getAttribute('clientHeight'); - const heightWithNewline = await dscTableRows[1].getAttribute('clientHeight'); - log.debug(`Without newlines: ${heightWithoutNewline}, With newlines: ${heightWithNewline}`); - - await common.sleep(10000); - return Number(heightWithNewline) > Number(heightWithoutNewline); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_esql_grid.ts b/test/functional/apps/discover/classic/_esql_grid.ts deleted file mode 100644 index 94dcabdba4efc..0000000000000 --- a/test/functional/apps/discover/classic/_esql_grid.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const security = getService('security'); - const dataGrid = getService('dataGrid'); - const dashboardAddPanel = getService('dashboardAddPanel'); - const dashboardPanelActions = getService('dashboardPanelActions'); - const { common, discover, dashboard, header, timePicker } = getPageObjects([ - 'common', - 'discover', - 'dashboard', - 'header', - 'timePicker', - ]); - - const defaultSettings = { - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }; - - describe('discover esql grid with legacy setting', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({}); - }); - - it('should render esql view correctly', async function () { - const savedSearchESQL = 'testESQLWithLegacySetting'; - await header.waitUntilLoadingHasFinished(); - await discover.waitUntilSearchingHasFinished(); - - await testSubjects.existOrFail('docTableHeader'); - await testSubjects.missingOrFail('euiDataGridBody'); - - await discover.selectTextBaseLang(); - - await header.waitUntilLoadingHasFinished(); - await discover.waitUntilSearchingHasFinished(); - - await testSubjects.missingOrFail('docTableHeader'); - await testSubjects.existOrFail('euiDataGridBody'); - - await dataGrid.clickRowToggle({ rowIndex: 0 }); - - await testSubjects.existOrFail('docViewerFlyout'); - - await discover.saveSearch(savedSearchESQL); - - await common.navigateToApp('dashboard'); - await dashboard.clickNewDashboard(); - await timePicker.setDefaultAbsoluteRange(); - await dashboardAddPanel.clickOpenAddPanel(); - await dashboardAddPanel.addSavedSearch(savedSearchESQL); - await header.waitUntilLoadingHasFinished(); - - await testSubjects.missingOrFail('docTableHeader'); - await testSubjects.existOrFail('euiDataGridBody'); - - await dataGrid.clickRowToggle({ rowIndex: 0 }); - - await testSubjects.existOrFail('docViewerFlyout'); - - await dashboardPanelActions.removePanelByTitle(savedSearchESQL); - - await dashboardAddPanel.addSavedSearch('A Saved Search'); - - await header.waitUntilLoadingHasFinished(); - await testSubjects.existOrFail('docTableHeader'); - await testSubjects.missingOrFail('euiDataGridBody'); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_field_data.ts b/test/functional/apps/discover/classic/_field_data.ts deleted file mode 100644 index 2ebd49bb24ae2..0000000000000 --- a/test/functional/apps/discover/classic/_field_data.ts +++ /dev/null @@ -1,63 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, timePicker } = getPageObjects(['common', 'timePicker']); - const find = getService('find'); - const testSubjects = getService('testSubjects'); - - describe('discover tab', function describeIndexTests() { - this.tags('includeFirefox'); - before(async function () { - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': true, - 'doc_table:legacy': true, - }); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - it('doc view should show @timestamp and _source columns', async function () { - const expectedHeader = '@timestamp\n_source'; - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - const docHeaderText = await docHeader.getVisibleText(); - expect(docHeaderText).to.be(expectedHeader); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_field_data_with_fields_api.ts b/test/functional/apps/discover/classic/_field_data_with_fields_api.ts deleted file mode 100644 index 4932ba3e24348..0000000000000 --- a/test/functional/apps/discover/classic/_field_data_with_fields_api.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - const { common, timePicker } = getPageObjects(['common', 'timePicker']); - const find = getService('find'); - const esArchiver = getService('esArchiver'); - const testSubjects = getService('testSubjects'); - - describe('discover tab with new fields API', function describeIndexTests() { - before(async function () { - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': false, - 'doc_table:legacy': true, - }); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_hide_announcements.ts b/test/functional/apps/discover/classic/_hide_announcements.ts deleted file mode 100644 index df7fcbb628136..0000000000000 --- a/test/functional/apps/discover/classic/_hide_announcements.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - - describe('test hide announcements', function () { - before(async function () { - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should display try document explorer button', async function () { - await discover.selectIndexPattern('logstash-*'); - const tourButtonExists = await testSubjects.exists('tryDocumentExplorerButton'); - expect(tourButtonExists).to.be(true); - }); - - it('should not display try document explorer button', async function () { - await kibanaServer.uiSettings.update({ hideAnnouncements: true }); - await browser.refresh(); - const tourButtonExists = await testSubjects.exists('tryDocumentExplorerButton'); - expect(tourButtonExists).to.be(false); - }); - }); -} diff --git a/test/functional/apps/discover/classic/index.ts b/test/functional/apps/discover/classic/index.ts deleted file mode 100644 index fce8963d19082..0000000000000 --- a/test/functional/apps/discover/classic/index.ts +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, loadTestFile }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const browser = getService('browser'); - - describe('discover/classic', function () { - before(async function () { - await browser.setWindowSize(1300, 800); - }); - - after(async function unloadMakelogs() { - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - }); - - loadTestFile(require.resolve('./_discover_fields_api')); - loadTestFile(require.resolve('./_doc_table')); - loadTestFile(require.resolve('./_doc_table_newline')); - loadTestFile(require.resolve('./_field_data')); - loadTestFile(require.resolve('./_field_data_with_fields_api')); - loadTestFile(require.resolve('./_classic_table_doc_navigation')); - loadTestFile(require.resolve('./_hide_announcements')); - loadTestFile(require.resolve('./_esql_grid')); - }); -} diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts index 7e7a12840f76d..5fd8e97c8f059 100644 --- a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts @@ -40,8 +40,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); } + function expectBreakdown(breakdown: string) { + return retry.try(async () => { + const breakdownFieldValue = await discover.getBreakdownFieldValue(); + expect(breakdownFieldValue).to.be(breakdown); + }); + } + describe('ES|QL mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -57,9 +64,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching index patterns', async () => { + it('should render state when switching index patterns', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -83,9 +91,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -111,6 +120,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { @@ -131,7 +141,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('data view mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -144,9 +154,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching data views', async () => { + it('should render default state when switching data views', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -166,9 +177,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -190,6 +202,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { diff --git a/test/functional/apps/discover/group1/_date_nanos_mixed.ts b/test/functional/apps/discover/group1/_date_nanos_mixed.ts index 7162d01bb96cc..a30c4a316351c 100644 --- a/test/functional/apps/discover/group1/_date_nanos_mixed.ts +++ b/test/functional/apps/discover/group1/_date_nanos_mixed.ts @@ -45,14 +45,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('shows a list of records of indices with date & date_nanos fields in the right order', async function () { - const isLegacy = await discover.useLegacyTable(); const rowData1 = await discover.getDocTableIndex(1); expect(rowData1).to.contain('Jan 1, 2019 @ 12:10:30.124000000'); - const rowData2 = await discover.getDocTableIndex(isLegacy ? 3 : 2); + const rowData2 = await discover.getDocTableIndex(2); expect(rowData2).to.contain('Jan 1, 2019 @ 12:10:30.123498765'); - const rowData3 = await discover.getDocTableIndex(isLegacy ? 5 : 3); + const rowData3 = await discover.getDocTableIndex(3); expect(rowData3).to.contain('Jan 1, 2019 @ 12:10:30.123456789'); - const rowData4 = await discover.getDocTableIndex(isLegacy ? 7 : 4); + const rowData4 = await discover.getDocTableIndex(4); expect(rowData4).to.contain('Jan 1, 2019 @ 12:10:30.123000000'); }); }); diff --git a/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts index b50cd7e16cf01..e801b40a80036 100644 --- a/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts +++ b/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts @@ -52,9 +52,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.changeDensityValue('Normal'); // toggle the popover - // Right now changing the density closes the popover (see packages/kbn-unified-data-table/src/components/data_table.tsx:1144) - // When that workaround is removed we will need to uncomment this next line - // await dataGrid.clickGridSettings(); + await dataGrid.clickGridSettings(); await dataGrid.clickGridSettings(); expect(await dataGrid.getCurrentDensityValue()).to.be('Normal'); }); @@ -62,7 +60,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should persist the density selection after reloading the page', async () => { await dataGrid.clickGridSettings(); await dataGrid.changeDensityValue('Expanded'); - await dataGrid.clickGridSettings(); expect(await dataGrid.getCurrentDensityValue()).to.be('Expanded'); await browser.refresh(); diff --git a/test/functional/apps/discover/group6/_sidebar.ts b/test/functional/apps/discover/group6/_sidebar.ts index a88623bb58d12..01adcb7a0a907 100644 --- a/test/functional/apps/discover/group6/_sidebar.ts +++ b/test/functional/apps/discover/group6/_sidebar.ts @@ -28,10 +28,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const fieldEditor = getService('fieldEditor'); const dataViews = getService('dataViews'); + const queryBar = getService('queryBar'); const retry = getService('retry'); const dataGrid = getService('dataGrid'); + const log = getService('log'); const INITIAL_FIELD_LIST_SUMMARY = '48 available fields. 5 empty fields. 4 meta fields.'; + const expectFieldListDescription = async (expectedNumber: string) => { + return await retry.try(async () => { + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + const ariaDescription = await unifiedFieldList.getSidebarAriaDescription(); + if (ariaDescription !== expectedNumber) { + log.warning( + `Expected Sidebar Aria Description: ${expectedNumber}, got: ${ariaDescription}` + ); + await queryBar.submitQuery(); + } + expect(ariaDescription).to.be(expectedNumber); + }); + }; + describe('discover sidebar', function describeIndexTests() { before(async function () { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); @@ -65,35 +82,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.waitUntilSidebarHasLoaded(); await unifiedFieldList.openSidebarFieldFilter(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await testSubjects.click('typeFilter-keyword'); - - await retry.waitFor('first updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '6 available fields. 1 empty field. 3 meta fields.' - ); - }); + // first update + await expectFieldListDescription('6 available fields. 1 empty field. 3 meta fields.'); await testSubjects.click('typeFilter-number'); - await retry.waitFor('second updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '10 available fields. 3 empty fields. 4 meta fields.' - ); - }); + // second update + await expectFieldListDescription('10 available fields. 3 empty fields. 4 meta fields.'); await testSubjects.click('fieldListFiltersFieldTypeFilterClearAll'); - await retry.waitFor('reset', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should show filters by type in ES|QL view', async function () { @@ -114,18 +117,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { options = await find.allByCssSelector('[data-test-subj*="typeFilter"]'); expect(options).to.have.length(6); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); - + await expectFieldListDescription('76 available fields. 6 empty fields.'); await testSubjects.click('typeFilter-number'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 2 empty fields.' - ); - }); + await expectFieldListDescription('4 available fields. 2 empty fields.'); }); it('should show empty fields in ES|QL view', async function () { @@ -138,52 +132,29 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await unifiedFieldList.waitUntilSidebarHasLoaded(); await unifiedFieldList.openSidebarFieldFilter(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '2 selected fields. 1 available field. 1 empty field.' - ); + await expectFieldListDescription('2 selected fields. 1 available field. 1 empty field.'); }); }); describe('search', function () { beforeEach(async () => { - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); afterEach(async () => { const fieldSearch = await testSubjects.find('clearSearchButton'); await fieldSearch.click(); - await retry.waitFor('reset', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should be able to search by string', async function () { await unifiedFieldList.findFieldByName('i'); - await retry.waitFor('first updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '28 available fields. 2 empty fields. 3 meta fields.' - ); - }); - + await expectFieldListDescription('28 available fields. 2 empty fields. 3 meta fields.'); await unifiedFieldList.findFieldByName('p'); - - await retry.waitFor('second updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'clientip, ip, relatedContent.og:description, relatedContent.twitter:description' @@ -192,13 +163,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search by wildcard', async function () { await unifiedFieldList.findFieldByName('relatedContent*image'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '2 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('2 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.og:image, relatedContent.twitter:image' @@ -208,12 +173,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with spaces as wildcard', async function () { await unifiedFieldList.findFieldByName('relatedContent image'); - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.og:image, relatedContent.og:image:height, relatedContent.og:image:width, relatedContent.twitter:image' @@ -222,13 +182,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with fuzzy search (1 typo)', async function () { await unifiedFieldList.findFieldByName('rel4tedContent.art'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.article:modified_time, relatedContent.article:published_time, relatedContent.article:section, relatedContent.article:tag' @@ -243,9 +197,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); // expect no changes in the list - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); }); @@ -345,10 +297,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect((await unifiedFieldList.getSidebarSectionFieldNames('meta')).join(', ')).to.be( '_id, _ignored, _index, _score' ); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should show field list groups excluding subfields when searched from source', async function () { @@ -387,7 +336,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'relatedContent' ); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '48 available fields. 1 unmapped field. 5 empty fields. 4 meta fields.' ); }); @@ -406,7 +355,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(availableFields.includes('extension')).to.be(true); expect(availableFields.includes('@message')).to.be(true); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '2 selected fields. 2 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); @@ -426,52 +375,35 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { '@message, _id, extension' ); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); // verify popular fields were persisted await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); }); it('should show selected and available fields in ES|QL mode', async function () { - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.selectTextBaseLang(); await monacoEditor.setCodeEditorValue('from logstash-* | limit 10000'); await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); + await expectFieldListDescription('76 available fields. 6 empty fields.'); await unifiedFieldList.clickFieldListItemRemove('extension'); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); + await expectFieldListDescription('76 available fields. 6 empty fields.'); const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '2 selected fields. 2 available fields.' - ); + await expectFieldListDescription('2 selected fields. 2 available fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('selected')).join(', ')).to.be( 'countB, geo.dest' ); @@ -480,12 +412,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedSearch.switchDataView('discover-dataView-switch-link', 'logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '48 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('48 available fields. 5 empty fields. 4 meta fields.'); }); it('should work correctly for a data view for a missing index', async function () { @@ -494,20 +421,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 0 meta fields.' - ); + await expectFieldListDescription('0 available fields. 0 meta fields.'); await testSubjects.missingOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}-fetchWarning` ); @@ -517,12 +435,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); @@ -537,41 +450,22 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('without-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '6 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); await testSubjects.existOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}NoFieldsCallout-noFieldsMatch` ); await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' @@ -583,11 +477,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should work when filters change', async () => { - await header.waitUntilLoadingHasFinished(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await unifiedFieldList.clickFieldListItem('extension'); expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( @@ -595,12 +485,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'jpg' }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); // check that the filter was passed down to the sidebar await unifiedFieldList.clickFieldListItem('extension'); @@ -614,29 +500,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('indices-stats*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '6873 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6873 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/many_fields_data_view' @@ -650,12 +522,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { adHoc: true, hasTimeField: true, }); - await discover.waitUntilSearchingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.addRuntimeField( '_bytes-runtimefield', @@ -666,12 +534,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); let allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield')).to.be(true); @@ -685,23 +548,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(true); expect(allFields.includes('_bytes-runtimefield')).to.be(false); await discover.removeField('_bytes-runtimefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(false); @@ -709,11 +562,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should render even when retrieving documents failed with an error', async () => { - await header.waitUntilLoadingHasFinished(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.addRuntimeField('_invalid-runtimefield', `emit(‘’);`); @@ -725,9 +574,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.waitUntilSidebarHasLoaded(); // check that the sidebar is rendered - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); let allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_invalid-runtimefield')).to.be(true); @@ -754,20 +601,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); await testSubjects.existOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}NoFieldsCallout-noFieldsMatch` ); @@ -777,12 +615,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Sep 23, 2019 @ 00:00:00.000' ); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '7 available fields. 4 meta fields.' - ); + await expectFieldListDescription('7 available fields. 4 meta fields.'); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' diff --git a/test/functional/apps/discover/group6/_time_field_column.ts b/test/functional/apps/discover/group6/_time_field_column.ts index 5965b7765e182..9e5ce3f94a459 100644 --- a/test/functional/apps/discover/group6/_time_field_column.ts +++ b/test/functional/apps/discover/group6/_time_field_column.ts @@ -34,7 +34,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dataViews = getService('dataViews'); const testSubjects = getService('testSubjects'); const security = getService('security'); - const docTable = getService('docTable'); const defaultSettings = { defaultIndex: 'logstash-*', hideAnnouncements: true, @@ -228,7 +227,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ ...defaultSettings, - 'doc_table:legacy': false, 'doc_table:hideTimeColumn': hideTimeFieldColumnSetting, }); await common.navigateToApp('discover'); @@ -319,103 +317,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); - - // These tests are skipped as they take a lot of time to run. Temporary unskip them to validate current functionality if necessary. - describe.skip('legacy table', () => { - beforeEach(async () => { - await kibanaServer.uiSettings.update({ - ...defaultSettings, - 'doc_table:hideTimeColumn': hideTimeFieldColumnSetting, - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should render initial columns correctly', async () => { - // no columns - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['Summary'] : ['@timestamp', 'Summary'] - ); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['Summary']); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}ESQL`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['Summary'] : ['@timestamp', 'Summary'] - ); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}ESQLdrop`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['Summary']); - - // only @timestamp is selected - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['@timestamp'] : ['@timestamp', '@timestamp'] - ); - - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['@timestamp']); - - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}ESQL`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['@timestamp'] : ['@timestamp', 'Summary'] - ); - }); - - it('should render selected columns correctly', async () => { - // with selected columns - await discover.loadSavedSearch(`${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting - ? ['bytes', 'extension'] - : ['@timestamp', 'bytes', 'extension'] - ); - - await discover.loadSavedSearch(`${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['bytes', 'extension']); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}ESQL` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['bytes', 'extension']); - - // with selected columns and @timestamp - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting - ? ['bytes', 'extension', '@timestamp'] - : ['@timestamp', 'bytes', 'extension', '@timestamp'] - ); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}-` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['bytes', 'extension', '@timestamp']); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}ESQL` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['bytes', 'extension', '@timestamp']); - }); - }); }); }); }); diff --git a/test/functional/apps/discover/group6/_view_mode_toggle.ts b/test/functional/apps/discover/group6/_view_mode_toggle.ts index 2591716c87d00..4ff5339b80847 100644 --- a/test/functional/apps/discover/group6/_view_mode_toggle.ts +++ b/test/functional/apps/discover/group6/_view_mode_toggle.ts @@ -33,102 +33,75 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update(defaultSettings); + await common.navigateToApp('discover'); + await discover.waitUntilSearchingHasFinished(); }); after(async () => { await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.replace({}); }); - [true, false].forEach((useLegacyTable) => { - describe(`isLegacy: ${useLegacyTable}`, function () { - before(async function () { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - ...defaultSettings, - 'doc_table:legacy': useLegacyTable, - }); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should show Documents tab', async () => { - await testSubjects.existOrFail('dscViewModeToggle'); - - if (!useLegacyTable) { - await testSubjects.existOrFail('unifiedDataTableToolbar'); - } - - const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); - expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); - }); - - it('should show legacy Document Explorer info callout', async () => { - if (useLegacyTable) { - await testSubjects.existOrFail('dscDocumentExplorerLegacyCallout'); - } else { - await testSubjects.missingOrFail('dscDocumentExplorerLegacyCallout'); - } - }); - - it('should show an error callout', async () => { - await queryBar.setQuery('@message::'); // invalid - await queryBar.submitQuery(); - await header.waitUntilLoadingHasFinished(); - - await discover.showsErrorCallout(); - - await queryBar.clearQuery(); - await queryBar.submitQuery(); - await header.waitUntilLoadingHasFinished(); - - await testSubjects.missingOrFail('discoverErrorCalloutTitle'); - }); - - describe('Patterns tab (basic license)', function () { - this.tags('skipFIPS'); - - it('should not show', async function () { - await testSubjects.missingOrFail('dscViewModePatternAnalysisButton'); - }); - }); - - it('should not show Field Statistics tab', async () => { - await testSubjects.existOrFail('dscViewModeToggle'); - }); - - it('should not show view mode toggle for ES|QL searches', async () => { - await testSubjects.click('dscViewModeDocumentButton'); - - await retry.try(async () => { - const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); - expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); - }); - - await testSubjects.existOrFail('dscViewModeToggle'); - - await discover.selectTextBaseLang(); - - await testSubjects.missingOrFail('dscViewModeToggle'); - await testSubjects.existOrFail('discoverQueryTotalHits'); - - if (!useLegacyTable) { - await testSubjects.existOrFail('unifiedDataTableToolbar'); - } - }); - - it('should show ES|QL columns callout', async () => { - await testSubjects.missingOrFail('dscSelectedColumnsCallout'); - await unifiedFieldList.clickFieldListItemAdd('extension'); - await header.waitUntilLoadingHasFinished(); - await testSubjects.existOrFail('dscSelectedColumnsCallout'); - }); + it('should show Documents tab', async () => { + await testSubjects.existOrFail('dscViewModeToggle'); + await testSubjects.existOrFail('unifiedDataTableToolbar'); + + const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); + expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); + }); + + it('should show an error callout', async () => { + await queryBar.setQuery('@message::'); // invalid + await queryBar.submitQuery(); + await header.waitUntilLoadingHasFinished(); + + await discover.showsErrorCallout(); + + await queryBar.clearQuery(); + await queryBar.submitQuery(); + await header.waitUntilLoadingHasFinished(); + + await testSubjects.missingOrFail('discoverErrorCalloutTitle'); + }); + + describe('Patterns tab (basic license)', function () { + this.tags('skipFIPS'); + + it('should not show', async function () { + await testSubjects.missingOrFail('dscViewModePatternAnalysisButton'); + }); + }); + + it('should not show Field Statistics tab', async () => { + await testSubjects.existOrFail('dscViewModeToggle'); + }); + + it('should not show view mode toggle for ES|QL searches', async () => { + await testSubjects.click('dscViewModeDocumentButton'); + + await retry.try(async () => { + const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); + expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); }); + + await testSubjects.existOrFail('dscViewModeToggle'); + + await discover.selectTextBaseLang(); + + await testSubjects.missingOrFail('dscViewModeToggle'); + await testSubjects.existOrFail('discoverQueryTotalHits'); + await testSubjects.existOrFail('unifiedDataTableToolbar'); + }); + + it('should show ES|QL columns callout', async () => { + await testSubjects.missingOrFail('dscSelectedColumnsCallout'); + await unifiedFieldList.clickFieldListItemAdd('extension'); + await header.waitUntilLoadingHasFinished(); + await testSubjects.existOrFail('dscSelectedColumnsCallout'); }); }); } diff --git a/test/functional/apps/discover/group7/_runtime_fields_editor.ts b/test/functional/apps/discover/group7/_runtime_fields_editor.ts index ab8711c362b77..e93e73650b464 100644 --- a/test/functional/apps/discover/group7/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/group7/_runtime_fields_editor.ts @@ -234,17 +234,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // navigate to doc view const fieldName = '_runtimefield-doc-view'; await createRuntimeField(fieldName); - const table = await discover.getDocTable(); - const useLegacyTable = await discover.useLegacyTable(); - await table.clickRowToggle(); + await dataGrid.clickRowToggle(); // click the open action await retry.try(async () => { - const rowActions = await table.getRowActions({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); if (!rowActions.length) { throw new Error('row actions empty, trying again'); } - const idxToClick = useLegacyTable ? 1 : 0; + const idxToClick = 0; await rowActions[idxToClick].click(); }); diff --git a/test/functional/apps/discover/group8/_hide_announcements.ts b/test/functional/apps/discover/group8/_hide_announcements.ts deleted file mode 100644 index 9dc11f9eefcac..0000000000000 --- a/test/functional/apps/discover/group8/_hide_announcements.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - const security = getService('security'); - - describe('test hide announcements', function () { - before(async function () { - await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should display callout', async function () { - await discover.selectIndexPattern('logstash-*'); - const calloutExists = await testSubjects.exists('dscDocumentExplorerLegacyCallout'); - expect(calloutExists).to.be(true); - }); - - it('should not display callout', async function () { - await kibanaServer.uiSettings.update({ hideAnnouncements: true }); - await browser.refresh(); - const calloutExists = await testSubjects.exists('dscDocumentExplorerLegacyCallout'); - expect(calloutExists).to.be(false); - }); - }); -} diff --git a/test/functional/apps/discover/group8/index.ts b/test/functional/apps/discover/group8/index.ts index 14b544e2c2015..46d5040fee298 100644 --- a/test/functional/apps/discover/group8/index.ts +++ b/test/functional/apps/discover/group8/index.ts @@ -23,7 +23,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./_default_route')); - loadTestFile(require.resolve('./_hide_announcements')); loadTestFile(require.resolve('./_flyouts')); }); } diff --git a/test/functional/apps/management/data_views/_handle_alias.ts b/test/functional/apps/management/data_views/_handle_alias.ts index a3b8a0266dae4..ca9f2b1f8cfea 100644 --- a/test/functional/apps/management/data_views/_handle_alias.ts +++ b/test/functional/apps/management/data_views/_handle_alias.ts @@ -18,8 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover', 'timePicker']); const kibanaServer = getService('kibanaServer'); - // Failing: See https://github.com/elastic/kibana/issues/201744 - describe.skip('Index patterns on aliases', function () { + describe('Index patterns on aliases', function () { before(async function () { await kibanaServer.savedObjects.cleanStandardList(); await security.testUser.setRoles(['kibana_admin', 'test_alias_reader']); diff --git a/test/functional/apps/management/data_views/_scripted_fields.ts b/test/functional/apps/management/data_views/_scripted_fields.ts index f86ae72aa5047..df51514425a24 100644 --- a/test/functional/apps/management/data_views/_scripted_fields.ts +++ b/test/functional/apps/management/data_views/_scripted_fields.ts @@ -387,14 +387,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('docTableHeaderFieldSort_@timestamp'); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\ntrue'); }); await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\nfalse'); }); }); @@ -469,14 +469,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('docTableHeaderFieldSort_@timestamp'); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); }); await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); }); }); diff --git a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts b/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts deleted file mode 100644 index 4f3d30222e496..0000000000000 --- a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts +++ /dev/null @@ -1,463 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// Tests for 4 scripted fields; -// 1. Painless (number type) -// 2. Painless (string type) -// 3. Painless (boolean type) -// 4. Painless (date type) -// -// Each of these scripted fields has 4 tests (12 tests total); -// 1. Create scripted field -// 2. See the expected value of the scripted field in Discover doc view -// 3. Filter in Discover by the scripted field -// 4. Visualize with aggregation on the scripted field by clicking unifiedFieldList.clickFieldListItemVisualize - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const kibanaServer = getService('kibanaServer'); - const log = getService('log'); - const browser = getService('browser'); - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); - const filterBar = getService('filterBar'); - const docTable = getService('docTable'); - const PageObjects = getPageObjects([ - 'common', - 'header', - 'settings', - 'visualize', - 'discover', - 'timePicker', - 'unifiedFieldList', - ]); - - describe('scripted fields', function () { - this.tags(['skipFirefox']); - - before(async function () { - await browser.setWindowSize(1200, 800); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, - }); - }); - - after(async function afterAll() { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - }); - - it('should not allow saving of invalid scripts', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - await PageObjects.settings.clickScriptedFieldsTab(); - await PageObjects.settings.clickAddScriptedField(); - await PageObjects.settings.setScriptedFieldName('doomedScriptedField'); - await PageObjects.settings.setScriptedFieldScript(`i n v a l i d s c r i p t`); - await PageObjects.settings.clickSaveScriptedField(); - await retry.try(async () => { - const invalidScriptErrorExists = await testSubjects.exists('invalidScriptError'); - expect(invalidScriptErrorExists).to.be(true); - }); - }); - - describe('testing regression for issue #33251', function describeIndexTests() { - const scriptedPainlessFieldName = 'ram_Pain_reg'; - - it('should create and edit scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - const script = `1`; - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName, - 'painless', - 'number', - null, - '1', - script - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - - for (let i = 0; i < 3; i++) { - await PageObjects.settings.editScriptedField(scriptedPainlessFieldName); - const fieldSaveButton = await testSubjects.exists('fieldSaveButton'); - expect(fieldSaveButton).to.be(true); - await PageObjects.settings.clickSaveScriptedField(); - } - }); - }); - - describe('creating and using Painless numeric scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName = 'ram_Pain1'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - const script = `if (doc['machine.ram'].size() == 0) return -1; - else return doc['machine.ram'].value / (1024 * 1024 * 1024); - `; - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName, - 'painless', - 'number', - null, - '100', - script - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); - }); - }); - - // add a test to sort numeric scripted field - it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181\n-1'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\n20'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName); - await log.debug('filter by the first value (14) in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName, - '14' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('31'); - }); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await filterBar.removeAllFilters(); - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - '@timestamp', - 'Median of ram_Pain1' - ); - }); - }); - - describe('creating and using Painless string scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painString'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'string', - null, - '1', - "if (doc['response.raw'].value == '200') { return 'good'} else { return 'bad'}" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); - }); - }); - - // add a test to sort string scripted field - it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594\nbad'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\ngood'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); - await log.debug('filter by "bad" in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName2, - 'bad' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('27'); - }); - await filterBar.removeAllFilters(); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - 'Top 5 values of painString' - ); - }); - }); - - describe('creating and using Painless boolean scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painBool'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'boolean', - null, - '1', - "doc['response.raw'].value == '200'" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); - await log.debug('filter by "true" in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName2, - 'true' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('359'); - }); - await filterBar.removeAllFilters(); - }); - - // add a test to sort boolean - // existing bug: https://github.com/elastic/kibana/issues/75519 hence the issue is skipped. - it.skip('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\ntrue'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\nfalse'); - }); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - 'Top 5 values of painBool' - ); - }); - }); - - describe('creating and using Painless date scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painDate'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'date', - { format: 'date', datePattern: 'YYYY-MM-DD HH:00' }, - '1', - "doc['utc_time'].value.toEpochMilli() + (1000) * 60 * 60" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 19:22:00.000'; - const toTime = 'Sep 18, 2015 @ 07:00:00.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); - }); - }); - - // add a test to sort date scripted field - // https://github.com/elastic/kibana/issues/75711 - it.skip('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.header.waitUntilLoadingHasFinished(); - await docTable.toggleRowExpanded(); - const firstRow = await docTable.getDetailsRow(); - await docTable.addInclusiveFilter(firstRow, scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('1'); - }); - await filterBar.removeAllFilters(); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain('painDate'); - }); - }); - }); -} diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 2300543f06d51..962aa41bd8ba3 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -31,7 +31,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_mgmt_import_saved_objects')); loadTestFile(require.resolve('./data_views/_index_patterns_empty')); loadTestFile(require.resolve('./data_views/_scripted_fields')); - loadTestFile(require.resolve('./data_views/_scripted_fields_classic_table')); loadTestFile(require.resolve('./data_views/_runtime_fields')); loadTestFile(require.resolve('./data_views/_runtime_fields_composite')); loadTestFile(require.resolve('./data_views/_field_formatter')); diff --git a/test/functional/firefox/discover.config.ts b/test/functional/firefox/discover.config.ts index 7012a3bccad16..9c4c689f0e8ca 100644 --- a/test/functional/firefox/discover.config.ts +++ b/test/functional/firefox/discover.config.ts @@ -18,7 +18,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...baseConfig.getAll(), testFiles: [ - require.resolve('../apps/discover/classic'), require.resolve('../apps/discover/esql'), require.resolve('../apps/discover/group1'), require.resolve('../apps/discover/group2_data_grid1'), diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index a80f3426e256e..30a4b27c3f037 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -52,6 +52,13 @@ export class ConsolePageObject extends FtrService { await textArea.clearValueWithKeyboard(); } + public async focusInputEditor() { + const outputEditor = await this.testSubjects.find('consoleMonacoEditor'); + // Simply clicking on the editor doesn't focus it, so we need to click + // on the margin view overlays + await (await outputEditor.findByClassName('margin-view-overlays')).click(); + } + public async focusOutputEditor() { const outputEditor = await this.testSubjects.find('consoleMonacoOutput'); // Simply clicking on the output editor doesn't focus it, so we need to click diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 2a263e9aa8ca7..c9ba5b0c5fa88 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -49,7 +49,6 @@ export class DashboardPageObject extends FtrService { private readonly common = this.ctx.getPageObject('common'); private readonly header = this.ctx.getPageObject('header'); private readonly visualize = this.ctx.getPageObject('visualize'); - private readonly discover = this.ctx.getPageObject('discover'); private readonly appsMenu = this.ctx.getService('appsMenu'); private readonly toasts = this.ctx.getService('toasts'); @@ -271,22 +270,12 @@ export class DashboardPageObject extends FtrService { */ public async expectToolbarPaginationDisplayed() { - const isLegacyDefault = await this.discover.useLegacyTable(); - if (isLegacyDefault) { - const subjects = [ - 'pagination-button-previous', - 'pagination-button-next', - 'toolBarTotalDocsText', - ]; - await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); - } else { - const subjects = ['pagination-button-previous', 'pagination-button-next']; + const subjects = ['pagination-button-previous', 'pagination-button-next']; - await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); - const paginationListExists = await this.find.existsByCssSelector('.euiPagination__list'); - if (!paginationListExists) { - throw new Error(`expected discover data grid pagination list to exist`); - } + await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); + const paginationListExists = await this.find.existsByCssSelector('.euiPagination__list'); + if (!paginationListExists) { + throw new Error(`expected discover data grid pagination list to exist`); } } diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 8feccfd955c7f..1f5945ff379f3 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -22,10 +22,8 @@ export class DiscoverPageObject extends FtrService { private readonly browser = this.ctx.getService('browser'); private readonly globalNav = this.ctx.getService('globalNav'); private readonly elasticChart = this.ctx.getService('elasticChart'); - private readonly docTable = this.ctx.getService('docTable'); private readonly config = this.ctx.getService('config'); private readonly dataGrid = this.ctx.getService('dataGrid'); - private readonly kibanaServer = this.ctx.getService('kibanaServer'); private readonly fieldEditor = this.ctx.getService('fieldEditor'); private readonly queryBar = this.ctx.getService('queryBar'); private readonly savedObjectsFinder = this.ctx.getService('savedObjectsFinder'); @@ -42,15 +40,6 @@ export class DiscoverPageObject extends FtrService { return await this.testSubjects.getAttribute('unifiedHistogramChart', 'data-time-range'); } - public async getDocTable() { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - return this.docTable; - } else { - return this.dataGrid; - } - } - public async saveSearch( searchName: string, saveAsNew?: boolean, @@ -117,12 +106,7 @@ export class DiscoverPageObject extends FtrService { } public async getColumnHeaders() { - const isLegacy = await this.useLegacyTable(); - if (isLegacy) { - return await this.docTable.getHeaderFields('embeddedSavedSearchDocTable'); - } - const table = await this.getDocTable(); - return await table.getHeaderFields(); + return await this.dataGrid.getHeaderFields(); } public async openLoadSavedSearchPanel() { @@ -224,6 +208,12 @@ export class DiscoverPageObject extends FtrService { ); } + public async getBreakdownFieldValue() { + const breakdownButton = await this.testSubjects.find('unifiedHistogramBreakdownSelectorButton'); + + return breakdownButton.getVisibleText(); + } + public async chooseBreakdownField(field: string, value?: string) { await this.retry.try(async () => { await this.testSubjects.click('unifiedHistogramBreakdownSelectorButton'); @@ -355,28 +345,16 @@ export class DiscoverPageObject extends FtrService { } public async getDocHeader() { - const table = await this.getDocTable(); - const docHeader = await table.getHeaders(); + const docHeader = await this.dataGrid.getHeaders(); return docHeader.join(); } public async getDocTableRows() { await this.header.waitUntilLoadingHasFinished(); - const table = await this.getDocTable(); - return await table.getBodyRows(); - } - - public async useLegacyTable() { - return (await this.kibanaServer.uiSettings.get('doc_table:legacy')) === true; + return await this.dataGrid.getBodyRows(); } public async getDocTableIndex(index: number, visibleText = false) { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - const row = await this.find.byCssSelector(`tr.kbnDocTable__row:nth-child(${index})`); - return await row.getVisibleText(); - } - const row = await this.dataGrid.getRow({ rowIndex: index - 1 }); const result = await Promise.all( row.map(async (cell) => { @@ -392,21 +370,10 @@ export class DiscoverPageObject extends FtrService { return result.slice(await this.dataGrid.getControlColumnsCount()).join(' '); } - public async getDocTableIndexLegacy(index: number) { - const row = await this.find.byCssSelector(`tr.kbnDocTable__row:nth-child(${index})`); - return await row.getVisibleText(); - } - public async getDocTableField(index: number, cellIdx: number = -1) { - const isLegacyDefault = await this.useLegacyTable(); - const usedDefaultCellIdx = isLegacyDefault ? 0 : await this.dataGrid.getControlColumnsCount(); + const usedDefaultCellIdx = await this.dataGrid.getControlColumnsCount(); const usedCellIdx = cellIdx === -1 ? usedDefaultCellIdx : cellIdx; - if (isLegacyDefault) { - const fields = await this.find.allByCssSelector( - `tr.kbnDocTable__row:nth-child(${index}) [data-test-subj='docTableField']` - ); - return await fields[usedCellIdx].getVisibleText(); - } + await this.testSubjects.click('dataGridFullScreenButton'); const row = await this.dataGrid.getRow({ rowIndex: index - 1 }); const result = await Promise.all(row.map(async (cell) => (await cell.getVisibleText()).trim())); @@ -414,33 +381,6 @@ export class DiscoverPageObject extends FtrService { return result[usedCellIdx]; } - public async clickDocTableRowToggle(rowIndex: number = 0) { - const docTable = await this.getDocTable(); - await docTable.clickRowToggle({ rowIndex }); - } - - public async skipToEndOfDocTable() { - // add the focus to the button to make it appear - const skipButton = await this.testSubjects.find('discoverSkipTableButton'); - // force focus on it, to make it interactable - await skipButton.focus(); - // now click it! - return skipButton.click(); - } - - /** - * When scrolling down the legacy table there's a link to scroll up - * So this is done by this function - */ - public async backToTop() { - const skipButton = await this.testSubjects.find('discoverBackToTop'); - return skipButton.click(); - } - - public async getDocTableFooter() { - return await this.testSubjects.find('discoverDocTableFooter'); - } - public isShowingDocViewer() { return this.dataGrid.isShowingDocViewer(); } @@ -472,7 +412,7 @@ export class DiscoverPageObject extends FtrService { } public async getMarks() { - const table = await this.docTable.getTable(); + const table = await this.dataGrid.getTable(); const marks = await table.findAllByTagName('mark'); return await Promise.all(marks.map((mark) => mark.getVisibleText())); } @@ -567,10 +507,6 @@ export class DiscoverPageObject extends FtrService { } public async clickFieldSort(field: string, text = 'Sort New-Old') { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - return await this.testSubjects.click(`docTableHeaderFieldSort_${field}`); - } return await this.dataGrid.clickDocSortAsc(field, text); } @@ -602,13 +538,7 @@ export class DiscoverPageObject extends FtrService { } public async removeHeaderColumn(name: string) { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - await this.testSubjects.moveMouseTo(`docTableHeader-${name}`); - await this.testSubjects.click(`docTableRemoveHeader-${name}`); - } else { - await this.dataGrid.clickRemoveColumn(name); - } + await this.dataGrid.clickRemoveColumn(name); } public async waitForChartLoadingComplete(renderCount: number) { diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index 414a44b24df97..ec43f1ec80120 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -81,14 +81,6 @@ export class DashboardExpectService extends FtrService { }); } - async docTableFieldCount(expectedCount: number) { - this.log.debug(`DashboardExpect.docTableFieldCount(${expectedCount})`); - await this.retry.try(async () => { - const docTableCells = await this.testSubjects.findAll('docTableField', this.findTimeout); - expect(docTableCells.length).to.be(expectedCount); - }); - } - async fieldSuggestions(expectedFields: string[]) { this.log.debug(`DashboardExpect.fieldSuggestions(${expectedFields})`); const fields = await this.filterBar.getFilterEditorFields(); diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index 3b17a31d624b6..4500bc5b97154 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -499,14 +499,6 @@ export class DataGridService extends FtrService { return await detailsRow.findAllByTestSubject('~docTableRowAction'); } - public async getAnchorDetailsRow(): Promise { - const table = await this.getTable(); - - return await table.findByCssSelector( - '[data-test-subj~="docTableAnchorRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - public async openColMenuByField(field: string) { await this.retry.waitFor('header cell action being displayed', async () => { // to prevent flakiness @@ -671,24 +663,6 @@ export class DataGridService extends FtrService { await sampleSizeInput.type(String(newValue)); } - public async getDetailsRow(): Promise { - const detailRows = await this.getDetailsRows(); - return detailRows[0]; - } - - public async getTableDocViewRow( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - return await detailsRow.findByTestSubject(`~tableDocViewRow-${fieldName}`); - } - - public async getRemoveInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~removeInclusiveFilterButton`); - } - public async showFieldCellActionInFlyout(fieldName: string, actionName: string): Promise { const cellSelector = ['addFilterForValueButton', 'addFilterOutValueButton'].includes(actionName) ? `tableDocViewRow-${fieldName}-value` diff --git a/test/functional/services/doc_table.ts b/test/functional/services/doc_table.ts deleted file mode 100644 index 0ca243b7b412b..0000000000000 --- a/test/functional/services/doc_table.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; -import { FtrService } from '../ftr_provider_context'; - -interface SelectOptions { - isAnchorRow?: boolean; - rowIndex?: number; -} - -export class DocTableService extends FtrService { - private readonly testSubjects = this.ctx.getService('testSubjects'); - private readonly retry = this.ctx.getService('retry'); - private readonly header = this.ctx.getPageObject('header'); - - public async getTable(selector?: string) { - return await this.testSubjects.find(selector ? selector : 'docTable'); - } - - public async getRowsText() { - const table = await this.getTable(); - const $ = await table.parseDomContent(); - return $.findTestSubjects('~docTableRow') - .toArray() - .map((row: any) => $(row).text().trim()); - } - - public async getBodyRows(): Promise { - const table = await this.getTable(); - return await table.findAllByTestSubject('~docTableRow'); - } - - public async getAnchorRow(): Promise { - const table = await this.getTable(); - return await table.findByTestSubject('~docTableAnchorRow'); - } - - public async getRow({ - isAnchorRow = false, - rowIndex = 0, - }: SelectOptions = {}): Promise { - return isAnchorRow ? await this.getAnchorRow() : (await this.getBodyRows())[rowIndex]; - } - - public async getDetailsRow(): Promise { - const table = await this.getTable(); - return await table.findByCssSelector('[data-test-subj~="docTableDetailsRow"]'); - } - - public async getAnchorDetailsRow(): Promise { - const table = await this.getTable(); - return await table.findByCssSelector( - '[data-test-subj~="docTableAnchorRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - - public async clickRowToggle( - options: SelectOptions = { isAnchorRow: false, rowIndex: 0 } - ): Promise { - const row = await this.getRow(options); - const toggle = await row.findByTestSubject('~docTableExpandToggleColumn'); - await toggle.click(); - } - - public async getDetailsRows(): Promise { - const table = await this.getTable(); - return await table.findAllByCssSelector( - '[data-test-subj~="docTableRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - - public async getRowActions({ isAnchorRow = false, rowIndex = 0 }: SelectOptions = {}): Promise< - WebElementWrapper[] - > { - const detailsRow = isAnchorRow - ? await this.getAnchorDetailsRow() - : (await this.getDetailsRows())[rowIndex]; - return await detailsRow.findAllByTestSubject('~docTableRowAction'); - } - - public async getFields(options: { isAnchorRow: boolean } = { isAnchorRow: false }) { - const table = await this.getTable(); - const $ = await table.parseDomContent(); - const rowLocator = options.isAnchorRow ? '~docTableAnchorRow' : '~docTableRow'; - const rows = $.findTestSubjects(rowLocator).toArray(); - return rows.map((row: any) => - $(row) - .find('[data-test-subj~="docTableField"]') - .toArray() - .map((field: any) => $(field).text()) - ); - } - - public async getHeaderFields(selector?: string): Promise { - const table = await this.getTable(selector); - const $ = await table.parseDomContent(); - return $.findTestSubjects('~docTableHeaderField') - .toArray() - .map((field: any) => $(field).text().trim()); - } - - public async getHeaders(selector?: string): Promise { - return this.getHeaderFields(selector); - } - - public async getTableDocViewRow( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - return await detailsRow.findByTestSubject(`~tableDocViewRow-${fieldName}`); - } - - public async getAddInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~addInclusiveFilterButton`); - } - - public async addInclusiveFilter(detailsRow: WebElementWrapper, fieldName: string): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getAddInclusiveFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async getRemoveInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~removeInclusiveFilterButton`); - } - - public async removeInclusiveFilter( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getRemoveInclusiveFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async getAddExistsFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~addExistsFilterButton`); - } - - public async addExistsFilter(detailsRow: WebElementWrapper, fieldName: string): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getAddExistsFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async toggleRowExpanded({ - isAnchorRow = false, - rowIndex = 0, - }: SelectOptions = {}): Promise { - await this.clickRowToggle({ isAnchorRow, rowIndex }); - await this.header.awaitGlobalLoadingIndicatorHidden(); - return await this.retry.try(async () => { - const row = isAnchorRow ? await this.getAnchorRow() : (await this.getBodyRows())[rowIndex]; - const detailsRow = await row.findByXpath( - './following-sibling::*[@data-test-subj="docTableDetailsRow"]' - ); - return detailsRow.findByTestSubject('~docViewer'); - }); - } -} diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 77df85ef3e565..ccdc8cfec3957 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -30,7 +30,6 @@ import { DashboardDrilldownPanelActionsProvider, DashboardDrilldownsManageProvider, } from './dashboard'; -import { DocTableService } from './doc_table'; import { EmbeddingService } from './embedding'; import { FilterBarService } from './filter_bar'; import { FlyoutService } from './flyout'; @@ -62,7 +61,6 @@ export const services = { ...commonFunctionalUIServices, filterBar: FilterBarService, queryBar: QueryBarService, - docTable: DocTableService, png: PngService, screenshots: ScreenshotsService, snapshots: SnapshotsService, diff --git a/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts b/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts index 0a7a15f0c62e2..2afd1e13d040c 100644 --- a/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts +++ b/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts @@ -18,7 +18,11 @@ async function getDeprecations({ savedObjectsClient, }: GetDeprecationsContext): Promise { const deprecations: DeprecationsDetails[] = []; - const { total } = await savedObjectsClient.find({ type: 'test-deprecations-plugin', perPage: 1 }); + const { total } = await savedObjectsClient.find({ + type: 'test-deprecations-plugin', + perPage: 1, + namespaces: ['*'], + }); deprecations.push({ title: 'CorePluginDeprecationsPlugin plugin is deprecated', diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 83ef8629a6efc..8047994039e71 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -163,6 +163,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'monitoring.ui.enabled (boolean?)', 'monitoring.ui.min_interval_seconds (number?)', 'monitoring.ui.show_license_expiration (boolean?)', + 'monitoring.ui.logs.index (string?)', 'newsfeed.fetchInterval (duration?)', 'newsfeed.mainInterval (duration?)', 'newsfeed.service.pathTemplate (string?)', @@ -353,6 +354,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.upgrade_assistant.featureSet.migrateSystemIndices (boolean?)', 'xpack.upgrade_assistant.featureSet.mlSnapshots (boolean?)', 'xpack.upgrade_assistant.featureSet.reindexCorrectiveActions (boolean?)', + 'xpack.upgrade_assistant.featureSet.migrateDataStreams (boolean?)', 'xpack.upgrade_assistant.ui.enabled (boolean?)', 'xpack.observability.unsafe.alertDetails.metrics.enabled (boolean?)', 'xpack.observability.unsafe.alertDetails.logs.enabled (boolean?)', diff --git a/tsconfig.base.json b/tsconfig.base.json index 9dd73f15f8d1b..4e4fd087b3f38 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -96,6 +96,8 @@ "@kbn/app-link-test-plugin/*": ["test/plugin_functional/plugins/app_link_test/*"], "@kbn/application-usage-test-plugin": ["x-pack/test/usage_collection/plugins/application_usage_test"], "@kbn/application-usage-test-plugin/*": ["x-pack/test/usage_collection/plugins/application_usage_test/*"], + "@kbn/asset-inventory-plugin": ["x-pack/plugins/asset_inventory"], + "@kbn/asset-inventory-plugin/*": ["x-pack/plugins/asset_inventory/*"], "@kbn/audit-log-plugin": ["x-pack/test/security_api_integration/plugins/audit_log"], "@kbn/audit-log-plugin/*": ["x-pack/test/security_api_integration/plugins/audit_log/*"], "@kbn/avc-banner": ["packages/kbn-avc-banner"], @@ -756,6 +758,8 @@ "@kbn/default-nav-management/*": ["packages/default-nav/management/*"], "@kbn/default-nav-ml": ["packages/default-nav/ml"], "@kbn/default-nav-ml/*": ["packages/default-nav/ml/*"], + "@kbn/dependency-ownership": ["packages/kbn-dependency-ownership"], + "@kbn/dependency-ownership/*": ["packages/kbn-dependency-ownership/*"], "@kbn/dependency-usage": ["packages/kbn-dependency-usage"], "@kbn/dependency-usage/*": ["packages/kbn-dependency-usage/*"], "@kbn/dev-cli-errors": ["packages/kbn-dev-cli-errors"], @@ -1478,6 +1482,8 @@ "@kbn/resolver-test-plugin/*": ["x-pack/test/plugin_functional/plugins/resolver_test/*"], "@kbn/response-ops-feature-flag-service": ["packages/response-ops/feature_flag_service"], "@kbn/response-ops-feature-flag-service/*": ["packages/response-ops/feature_flag_service/*"], + "@kbn/response-ops-rule-form": ["packages/response-ops/rule_form"], + "@kbn/response-ops-rule-form/*": ["packages/response-ops/rule_form/*"], "@kbn/response-ops-rule-params": ["packages/response-ops/rule_params"], "@kbn/response-ops-rule-params/*": ["packages/response-ops/rule_params/*"], "@kbn/response-stream-plugin": ["examples/response_stream"], @@ -1532,6 +1538,8 @@ "@kbn/saved-objects-tagging-oss-plugin/*": ["src/plugins/saved_objects_tagging_oss/*"], "@kbn/saved-objects-tagging-plugin": ["x-pack/plugins/saved_objects_tagging"], "@kbn/saved-objects-tagging-plugin/*": ["x-pack/plugins/saved_objects_tagging/*"], + "@kbn/saved-search-component": ["packages/kbn-saved-search-component"], + "@kbn/saved-search-component/*": ["packages/kbn-saved-search-component/*"], "@kbn/saved-search-plugin": ["src/plugins/saved_search"], "@kbn/saved-search-plugin/*": ["src/plugins/saved_search/*"], "@kbn/scout": ["packages/kbn-scout"], diff --git a/versions.json b/versions.json index 0843e7d912622..67e0a6ac49320 100644 --- a/versions.json +++ b/versions.json @@ -24,7 +24,7 @@ "previousMajor": true }, { - "version": "8.15.5", + "version": "8.15.6", "branch": "8.15", "previousMajor": true }, diff --git a/x-pack/examples/alerting_example/server/plugin.ts b/x-pack/examples/alerting_example/server/plugin.ts index 43b3bc82c4416..bf79d564222db 100644 --- a/x-pack/examples/alerting_example/server/plugin.ts +++ b/x-pack/examples/alerting_example/server/plugin.ts @@ -9,9 +9,10 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; // import directly to support examples functional tests (@kbn-test/src/functional_tests/lib/babel_register_for_test_plugins.js) import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; -import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { ruleType as alwaysFiringRule } from './rule_types/always_firing'; import { ruleType as peopleInSpaceRule } from './rule_types/astros'; @@ -22,7 +23,7 @@ import { ALERTING_EXAMPLE_APP_ID } from '../common/constants'; // this plugin's dependencies export interface AlertingExampleDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; } @@ -43,15 +44,54 @@ export class AlertingExamplePlugin implements Plugin ( ( { id: 'observabilityCases', configurationId: 'observabilityCases', alertsTableConfigurationRegistry, - featureIds: [ - AlertConsumers.INFRASTRUCTURE, - AlertConsumers.APM, - AlertConsumers.OBSERVABILITY, - AlertConsumers.LOGS, - ], + ruleTypeIds: ['.es-query'], query: { bool: { filter: [], diff --git a/x-pack/examples/triggers_actions_ui_example/server/plugin.ts b/x-pack/examples/triggers_actions_ui_example/server/plugin.ts index 6d55bbb2cb55d..6bf6c1fd1442e 100644 --- a/x-pack/examples/triggers_actions_ui_example/server/plugin.ts +++ b/x-pack/examples/triggers_actions_ui_example/server/plugin.ts @@ -8,7 +8,7 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { PluginSetupContract as ActionsSetup } from '@kbn/actions-plugin/server'; -import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { getConnectorType as getSystemLogExampleConnectorType, @@ -17,7 +17,7 @@ import { // this plugin's dependencies export interface TriggersActionsUiExampleDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; actions: ActionsSetup; } export class TriggersActionsUiExamplePlugin diff --git a/x-pack/examples/triggers_actions_ui_example/tsconfig.json b/x-pack/examples/triggers_actions_ui_example/tsconfig.json index 601f23edd2647..d0622a4c64965 100644 --- a/x-pack/examples/triggers_actions_ui_example/tsconfig.json +++ b/x-pack/examples/triggers_actions_ui_example/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/alerting-plugin", "@kbn/triggers-actions-ui-plugin", "@kbn/developer-examples-plugin", - "@kbn/rule-data-utils", "@kbn/data-plugin", "@kbn/i18n-react", "@kbn/shared-ux-router", @@ -29,8 +28,8 @@ "@kbn/charts-plugin", "@kbn/data-views-plugin", "@kbn/unified-search-plugin", - "@kbn/alerts-ui-shared", "@kbn/data-view-editor-plugin", "@kbn/react-kibana-context-render", + "@kbn/response-ops-rule-form", ] } diff --git a/x-pack/packages/ai-infra/product-doc-common/src/indices.ts b/x-pack/packages/ai-infra/product-doc-common/src/indices.ts index b48cacf79fd23..90e416ff48c46 100644 --- a/x-pack/packages/ai-infra/product-doc-common/src/indices.ts +++ b/x-pack/packages/ai-infra/product-doc-common/src/indices.ts @@ -7,9 +7,9 @@ import type { ProductName } from './product'; -export const productDocIndexPrefix = '.kibana-ai-product-doc'; -export const productDocIndexPattern = `${productDocIndexPrefix}-*`; +export const productDocIndexPrefix = '.kibana_ai_product_doc'; +export const productDocIndexPattern = `${productDocIndexPrefix}_*`; export const getProductDocIndexName = (productName: ProductName): string => { - return `${productDocIndexPrefix}-${productName.toLowerCase()}`; + return `${productDocIndexPrefix}_${productName.toLowerCase()}`; }; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx index b8ea673483372..00879b38932aa 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx @@ -509,7 +509,9 @@ export function ChatBody({ saveTitle(newTitle); }} onToggleFlyoutPositionMode={onToggleFlyoutPositionMode} - navigateToConversation={navigateToConversation} + navigateToConversation={ + initialMessages?.length && !initialConversationId ? undefined : navigateToConversation + } /> diff --git a/x-pack/packages/kbn-cloud-security-posture/common/constants.ts b/x-pack/packages/kbn-cloud-security-posture/common/constants.ts index a24d676dc6f88..9112dba4b9a4f 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/constants.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/constants.ts @@ -47,3 +47,8 @@ export const VULNERABILITIES_SEVERITY: Record = { CRITICAL: 'CRITICAL', UNKNOWN: 'UNKNOWN', }; + +export const MISCONFIGURATION_STATUS: Record = { + PASSED: 'passed', + FAILED: 'failed', +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/common/index.ts b/x-pack/packages/kbn-cloud-security-posture/common/index.ts index d5ee781c39b20..4065f7ca331a9 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/index.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/index.ts @@ -28,7 +28,9 @@ export * from './constants'; export { extractErrorMessage, buildMutedRulesFilter, - buildEntityFlyoutPreviewQuery, + buildGenericEntityFlyoutPreviewQuery, + buildMisconfigurationEntityFlyoutPreviewQuery, + buildVulnerabilityEntityFlyoutPreviewQuery, } from './utils/helpers'; export { getAbbreviatedNumber } from './utils/get_abbreviated_number'; export { UiMetricService } from './utils/ui_metrics'; diff --git a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts index 04cb76f4441c5..6b85d2ead28fe 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts @@ -9,8 +9,10 @@ import { extractErrorMessage, defaultErrorMessage, buildMutedRulesFilter, - buildEntityFlyoutPreviewQuery, buildEntityAlertsQuery, + buildGenericEntityFlyoutPreviewQuery, + buildMisconfigurationEntityFlyoutPreviewQuery, + buildVulnerabilityEntityFlyoutPreviewQuery, } from './helpers'; const fallbackMessage = 'thisIsAFallBackMessage'; @@ -145,7 +147,7 @@ describe('test helper methods', () => { }); }); - describe('buildEntityFlyoutPreviewQueryTest', () => { + describe('buildGenericEntityFlyoutPreviewQuery', () => { it('should return the correct query when given field and query', () => { const field = 'host.name'; const query = 'exampleHost'; @@ -162,10 +164,10 @@ describe('test helper methods', () => { }, }; - expect(buildEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery); + expect(buildGenericEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery); }); - it('should return the correct query when given field and empty query', () => { + it('should return the correct query when given field and empty query and empty status', () => { const field = 'host.name'; const expectedQuery = { bool: { @@ -180,12 +182,143 @@ describe('test helper methods', () => { }, }; - expect(buildEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery); + expect(buildGenericEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery); + }); + + it('should return the correct query when given field and queryValue and status but empty queryField', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const status = 'pass'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, status)).toEqual(expectedQuery); + }); + + it('should return the correct query when given field and queryValue and queryField but empty status', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const emptyStatus = undefined; + const queryField = 'some.field'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual( + expectedQuery + ); + }); + + it('should return the correct query when given all the parameters', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const emptyStatus = 'some.status'; + const queryField = 'some.field'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'some.field': 'some.status' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual( + expectedQuery + ); + }); + }); + + describe('buildMisconfigurationEntityFlyoutPreviewQuery', () => { + it('should return the correct query when given field, queryValue, status and queryType Misconfiguration', () => { + const field = 'host.name'; + const queryValue = 'exampleHost'; + const status = 'pass'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'result.evaluation': 'pass' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildMisconfigurationEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual( + expectedQuery + ); + }); + }); + describe('buildVulnerabilityEntityFlyoutPreviewQuery', () => { + it('should return the correct query when given field, queryValue, status and queryType Vulnerability', () => { + const field = 'host.name'; + const queryValue = 'exampleHost'; + const status = 'low'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'vulnerability.severity': 'low' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildVulnerabilityEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual( + expectedQuery + ); }); }); describe('buildEntityAlertsQuery', () => { - const getExpectedAlertsQuery = (size?: number) => { + const getExpectedAlertsQuery = (size?: number, severity?: string) => { return { size: size || 0, _source: false, @@ -202,20 +335,30 @@ describe('test helper methods', () => { filter: [ { bool: { - must: [], - filter: [ + should: [ { - match_phrase: { - 'host.name': { - query: 'exampleHost', - }, + term: { + 'host.name': 'exampleHost', }, }, ], - should: [], - must_not: [], + minimum_should_match: 1, }, }, + severity + ? { + bool: { + should: [ + { + term: { + 'kibana.alert.severity': 'low', + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, { range: { '@timestamp': { @@ -229,7 +372,7 @@ describe('test helper methods', () => { 'kibana.alert.workflow_status': ['open', 'acknowledged'], }, }, - ], + ].filter(Boolean), }, }, }; @@ -256,5 +399,18 @@ describe('test helper methods', () => { expect(buildEntityAlertsQuery(field, to, from, query)).toEqual(getExpectedAlertsQuery(size)); }); + + it('should return the correct query when given severity query', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const to = 'Tomorrow'; + const from = 'Today'; + const size = undefined; + const severity = 'low'; + + expect(buildEntityAlertsQuery(field, to, from, query, size, severity)).toEqual( + getExpectedAlertsQuery(size, 'low') + ); + }); }); }); diff --git a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts index bd531fa63804f..ac2e27b70878f 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts @@ -43,7 +43,12 @@ export const buildMutedRulesFilter = ( return mutedRulesFilterQuery; }; -export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string) => { +export const buildGenericEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string, + queryField?: string +) => { return { bool: { filter: [ @@ -59,17 +64,52 @@ export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string minimum_should_match: 1, }, }, - ], + status && queryField + ? { + bool: { + should: [ + { + term: { + [queryField]: status, + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, + ].filter(Boolean), }, }; }; +// Higher-order function for Misconfiguration +export const buildMisconfigurationEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string +) => { + const queryField = 'result.evaluation'; + return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField); +}; + +// Higher-order function for Vulnerability +export const buildVulnerabilityEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string +) => { + const queryField = 'vulnerability.severity'; + return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField); +}; + export const buildEntityAlertsQuery = ( field: string, to: string, from: string, queryValue?: string, - size?: number + size?: number, + severity?: string ) => { return { size: size || 0, @@ -87,20 +127,30 @@ export const buildEntityAlertsQuery = ( filter: [ { bool: { - must: [], - filter: [ + should: [ { - match_phrase: { - [field]: { - query: queryValue, - }, + term: { + [field]: `${queryValue || ''}`, }, }, ], - should: [], - must_not: [], + minimum_should_match: 1, }, }, + severity + ? { + bool: { + should: [ + { + term: { + 'kibana.alert.severity': severity, + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, { range: { '@timestamp': { @@ -114,7 +164,7 @@ export const buildEntityAlertsQuery = ( 'kibana.alert.workflow_status': ['open', 'acknowledged'], }, }, - ], + ].filter(Boolean), }, }, }; diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx index 898e12b5b4c01..6826c47b270ce 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx @@ -49,6 +49,8 @@ export function DefaultEdge({ path={edgePath} style={{ stroke: euiTheme.colors[color], + }} + css={{ strokeDasharray: '2,2', }} markerEnd={ diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx index 58ecea3bc3bea..5a3e2f8b72b21 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx @@ -128,7 +128,7 @@ export const SvgDefsMarker = () => { const { euiTheme } = useEuiTheme(); return ( - + diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx index 97b8928c421e1..a3dd064d16ab7 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx @@ -16,7 +16,7 @@ export const EdgeGroupNode: React.FC = memo((props: NodeProps) => { <> { return (
        diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts index d4d436e981cc4..3e22fdea80666 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts @@ -11,3 +11,6 @@ export const statusColors = { failed: euiThemeVars.euiColorVis9, unknown: euiThemeVars.euiColorLightShade, }; + +export const HOST_NAME = 'host.name'; +export const USER_NAME = 'user.name'; diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts index 9b126332b567b..c8e36898fed16 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useMisconfigurationPreview } from './use_misconfiguration_preview'; export const useHasMisconfigurations = (field: 'host.name' | 'user.name', value: string) => { const { data } = useMisconfigurationPreview({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildGenericEntityFlyoutPreviewQuery(field, value), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts index 336892ee888af..ae7e951ce9313 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useVulnerabilitiesPreview } from './use_vulnerabilities_preview'; import { hasVulnerabilitiesData } from '../utils/vulnerability_helpers'; export const useHasVulnerabilities = (field: 'host.name' | 'user.name', value: string) => { const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildGenericEntityFlyoutPreviewQuery(field, value), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts index 493e58519bd91..2c7be37de50dd 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts @@ -58,7 +58,7 @@ export interface CspClientPluginStartDeps { export interface CspBaseEsQuery { query?: { bool: { - filter: estypes.QueryDslQueryContainer[]; + filter: Array | undefined; }; }; } diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts index 898f9990a1a96..e2503b7a38a2c 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts @@ -10,6 +10,7 @@ import { getVulnerabilityStats } from './vulnerability_helpers'; import { i18n } from '@kbn/i18n'; describe('getVulnerabilitiesAggregationCount', () => { + const mockFilterFunction = jest.fn(); it('should return empty array when all severity count is 0', () => { const result = getVulnerabilityStats({ critical: 0, high: 0, medium: 0, low: 0, none: 0 }); expect(result).toEqual([]); @@ -17,8 +18,12 @@ describe('getVulnerabilitiesAggregationCount', () => { it('should return stats for low, medium, high, and critical vulnerabilities', () => { const result = getVulnerabilityStats({ critical: 1, high: 2, medium: 3, low: 4, none: 5 }); + const resultWithoutFunctions = result.map((item) => { + const { filter, reset, ...rest } = item; + return rest; + }); - expect(result).toEqual([ + expect(resultWithoutFunctions).toEqual([ { key: i18n.translate( 'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText', @@ -28,6 +33,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 5, color: '#aaa', + isCurrentFilter: false, }, { key: i18n.translate( @@ -38,6 +44,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 4, color: euiThemeVars.euiColorVis0, + isCurrentFilter: false, }, { key: i18n.translate( @@ -48,6 +55,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 3, color: euiThemeVars.euiColorVis5_behindText, + isCurrentFilter: false, }, { key: i18n.translate( @@ -58,6 +66,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 2, color: euiThemeVars.euiColorVis9_behindText, + isCurrentFilter: false, }, { key: i18n.translate( @@ -68,7 +77,43 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 1, color: euiThemeVars.euiColorDanger, + isCurrentFilter: false, }, ]); }); + + it('should return correct stats with correct onClick functions', () => { + const result = getVulnerabilityStats( + { critical: 1, high: 2, medium: 3, low: 4, none: 5 }, + mockFilterFunction + ); + const event = { stopPropagation: jest.fn() } as unknown as React.MouseEvent< + SVGElement, + MouseEvent + >; + result[1].filter?.(); + expect(mockFilterFunction).toHaveBeenCalledWith('LOW'); + result[1].reset?.(event); + expect(mockFilterFunction).toHaveBeenCalledWith(''); + }); + + it('should identify correct currentFilter', () => { + const currentFilter = 'LOW'; + const result = getVulnerabilityStats( + { critical: 1, high: 2, medium: 3, low: 4, none: 5 }, + mockFilterFunction, + currentFilter + ); + + // Make sure that Low is set to Current Filter + expect(result[1].isCurrentFilter).toBe(true); + expect(result[1].key).toBe('Low'); + + // Make sure only Low is set as Current Filter and no other severity + result.forEach((item) => { + if (item.key !== 'Low') { + expect(item.isCurrentFilter).toBe(false); + } + }); + }); }); diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts index c8782daf35308..e1bec795ad444 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts @@ -14,6 +14,9 @@ interface VulnerabilitiesDistributionBarProps { key: string; count: number; color: string; + isCurrentFilter?: boolean; + filter?: () => void; + reset?: (event: any) => void; } interface VulnerabilityCounts { @@ -30,7 +33,9 @@ export const hasVulnerabilitiesData = (counts: VulnerabilityCounts): boolean => }; export const getVulnerabilityStats = ( - counts: VulnerabilityCounts + counts: VulnerabilityCounts, + filterFunction?: (filter: string) => void, + currentFilter?: string ): VulnerabilitiesDistributionBarProps[] => { const vulnerabilityStats: VulnerabilitiesDistributionBarProps[] = []; @@ -50,6 +55,14 @@ export const getVulnerabilityStats = ( ), count: counts.none, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.UNKNOWN), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.UNKNOWN); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.UNKNOWN, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.low > 0) vulnerabilityStats.push({ @@ -61,6 +74,14 @@ export const getVulnerabilityStats = ( ), count: counts.low, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.LOW), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.LOW); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.LOW, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.medium > 0) @@ -73,6 +94,14 @@ export const getVulnerabilityStats = ( ), count: counts.medium, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.MEDIUM), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.MEDIUM); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.MEDIUM, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.high > 0) vulnerabilityStats.push({ @@ -84,6 +113,14 @@ export const getVulnerabilityStats = ( ), count: counts.high, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.HIGH), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.HIGH); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.HIGH, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.critical > 0) vulnerabilityStats.push({ @@ -95,6 +132,14 @@ export const getVulnerabilityStats = ( ), count: counts.critical, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.CRITICAL), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.CRITICAL); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.CRITICAL, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); return vulnerabilityStats; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx index c2ec745cc5c64..63c8adf37e5b8 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx @@ -8,6 +8,7 @@ import { KnowledgeBaseConfig } from '../assistant/types'; export const ATTACK_DISCOVERY_STORAGE_KEY = 'attackDiscovery'; +export const DEFEND_INSIGHTS_STORAGE_KEY = 'defendInsights'; export const DEFAULT_ASSISTANT_NAMESPACE = 'elasticAssistantDefault'; export const LAST_CONVERSATION_ID_LOCAL_STORAGE_KEY = 'lastConversationId'; export const MAX_ALERTS_LOCAL_STORAGE_KEY = 'maxAlerts'; diff --git a/x-pack/packages/kbn-elastic-assistant/index.ts b/x-pack/packages/kbn-elastic-assistant/index.ts index 7ec65c9601268..7f9ce6fe36c2f 100644 --- a/x-pack/packages/kbn-elastic-assistant/index.ts +++ b/x-pack/packages/kbn-elastic-assistant/index.ts @@ -83,6 +83,7 @@ export { /** The default maximum number of alerts to be sent as context when generating Attack discoveries */ DEFAULT_ATTACK_DISCOVERY_MAX_ALERTS, DEFAULT_LATEST_ALERTS, + DEFEND_INSIGHTS_STORAGE_KEY, KNOWLEDGE_BASE_LOCAL_STORAGE_KEY, /** The local storage key that specifies the maximum number of alerts to send as context */ MAX_ALERTS_LOCAL_STORAGE_KEY, diff --git a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts index 5df10e11bb7ed..c24da00d7724e 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts @@ -25,8 +25,9 @@ export interface MetadataRecord { export interface EntityV2 { 'entity.id': string; - 'entity.last_seen_timestamp': string; 'entity.type': string; + 'entity.display_name': string; + 'entity.last_seen_timestamp'?: string; [metadata: string]: any; } diff --git a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts index 0576f1cf328eb..c292d355b4867 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts @@ -27,16 +27,26 @@ const objectiveSchema = t.intersection([ t.partial({ timesliceTarget: t.number, timesliceWindow: durationType }), ]); -const settingsSchema = t.type({ +const settingsSchema = t.intersection([ + t.type({ + syncDelay: durationType, + frequency: durationType, + preventInitialBackfill: t.boolean, + }), + t.partial({ syncField: t.union([t.string, t.null]) }), +]); + +const groupBySchema = allOrAnyStringOrArray; + +const optionalSettingsSchema = t.partial({ syncDelay: durationType, frequency: durationType, preventInitialBackfill: t.boolean, + syncField: t.union([t.string, t.null]), }); -const groupBySchema = allOrAnyStringOrArray; - -const optionalSettingsSchema = t.partial({ ...settingsSchema.props }); const tagsSchema = t.array(t.string); + // id cannot contain special characters and spaces const sloIdSchema = new t.Type( 'sloIdSchema', diff --git a/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx b/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx index d9f68fe7ef890..6e44f01cbbd69 100644 --- a/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx +++ b/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx @@ -136,6 +136,8 @@ export interface DocumentCountChartProps { dataTestSubj?: string; /** Optional change point metadata */ changePoint?: DocumentCountStatsChangePoint; + /** Whether the brush should be non-interactive */ + nonInteractive?: boolean; } const SPEC_ID = 'document_count'; @@ -190,6 +192,7 @@ export const DocumentCountChart: FC = (props) => { barHighlightColorOverride, deviationBrush = {}, baselineBrush = {}, + nonInteractive, } = props; const { data, uiSettings, fieldFormats, charts } = dependencies; @@ -470,6 +473,7 @@ export const DocumentCountChart: FC = (props) => { marginLeft={mlBrushMarginLeft} snapTimestamps={snapTimestamps} width={mlBrushWidth} + nonInteractive={nonInteractive} /> diff --git a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx index 08b9fc5628297..932f509e164de 100644 --- a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx +++ b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx @@ -88,6 +88,11 @@ interface DualBrushProps { * Width */ width: number; + /** + * Whether the brush should be non-interactive. When true, the brush is still visible + * but cannot be moved or resized by the user. + */ + nonInteractive?: boolean; } /** @@ -98,7 +103,16 @@ interface DualBrushProps { * @returns The DualBrush component. */ export const DualBrush: FC = (props) => { - const { windowParameters, min, max, onChange, marginLeft, snapTimestamps, width } = props; + const { + windowParameters, + min, + max, + onChange, + marginLeft, + snapTimestamps, + width, + nonInteractive, + } = props; const d3BrushContainer = useRef(null); const brushes = useRef([]); @@ -301,6 +315,10 @@ export const DualBrush: FC = (props) => { .attr('rx', BRUSH_HANDLE_ROUNDED_CORNER) .attr('ry', BRUSH_HANDLE_ROUNDED_CORNER); + if (nonInteractive) { + mlBrushSelection.merge(mlBrushSelection).attr('pointer-events', 'none'); + } + mlBrushSelection.exit().remove(); } @@ -355,6 +373,7 @@ export const DualBrush: FC = (props) => { deviationMax, snapTimestamps, onChange, + nonInteractive, ]); return ( diff --git a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx index 173f33e08f0b4..7308185f99b65 100644 --- a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx +++ b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx @@ -40,6 +40,7 @@ interface ProgressControlProps { shouldRerunAnalysis: boolean; runAnalysisDisabled?: boolean; analysisInfo?: React.ReactNode; + isAnalysisControlsDisabled?: boolean; } /** @@ -63,6 +64,7 @@ export const ProgressControls: FC> = (pr shouldRerunAnalysis, runAnalysisDisabled = false, analysisInfo = null, + isAnalysisControlsDisabled = false, } = props; const progressOutput = Math.round(progress * 100); @@ -73,47 +75,55 @@ export const ProgressControls: FC> = (pr return ( - - {!isRunning && ( - - - - - - {shouldRerunAnalysis && ( - <> - - - - - )} - - - )} - {isRunning && ( - - - - )} - - {(progress === 1 || isRunning === false) && !isBrushCleared ? ( + {!isAnalysisControlsDisabled && ( + + {!isRunning && ( + + + + + + {shouldRerunAnalysis && ( + <> + + + + + )} + + + )} + {isRunning && ( + + + + )} + + )} + + {(progress === 1 || isRunning === false) && !isBrushCleared && !isAnalysisControlsDisabled ? ( ( {children} ); @@ -34,7 +38,7 @@ describe('useAlertsHistory', () => { const end = '2023-05-10T00:00:00.000Z'; const ruleId = 'cfd36e60-ef22-11ed-91eb-b7893acacfe2'; - afterEach(() => { + beforeEach(() => { jest.clearAllMocks(); }); @@ -44,7 +48,7 @@ describe('useAlertsHistory', () => { () => useAlertsHistory({ http, - featureIds: [AlertConsumers.APM], + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -61,16 +65,13 @@ describe('useAlertsHistory', () => { }); it('returns no data when API error', async () => { - const http = { - post: jest.fn().mockImplementation(() => { - throw new Error('ES error'); - }), - } as unknown as HttpSetup; + mockServices.http.post.mockRejectedValueOnce(new Error('ES error')); + const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -87,54 +88,53 @@ describe('useAlertsHistory', () => { }); it('returns the alert history chart data', async () => { - const http = { - post: jest.fn().mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - { key_as_string: '2023-04-11T00:00:00.000Z', key: 1681171200000, doc_count: 0 }, - { key_as_string: '2023-04-12T00:00:00.000Z', key: 1681257600000, doc_count: 0 }, - { key_as_string: '2023-04-13T00:00:00.000Z', key: 1681344000000, doc_count: 0 }, - { key_as_string: '2023-04-14T00:00:00.000Z', key: 1681430400000, doc_count: 0 }, - { key_as_string: '2023-04-15T00:00:00.000Z', key: 1681516800000, doc_count: 0 }, - { key_as_string: '2023-04-16T00:00:00.000Z', key: 1681603200000, doc_count: 0 }, - { key_as_string: '2023-04-17T00:00:00.000Z', key: 1681689600000, doc_count: 0 }, - { key_as_string: '2023-04-18T00:00:00.000Z', key: 1681776000000, doc_count: 0 }, - { key_as_string: '2023-04-19T00:00:00.000Z', key: 1681862400000, doc_count: 0 }, - { key_as_string: '2023-04-20T00:00:00.000Z', key: 1681948800000, doc_count: 0 }, - { key_as_string: '2023-04-21T00:00:00.000Z', key: 1682035200000, doc_count: 0 }, - { key_as_string: '2023-04-22T00:00:00.000Z', key: 1682121600000, doc_count: 0 }, - { key_as_string: '2023-04-23T00:00:00.000Z', key: 1682208000000, doc_count: 0 }, - { key_as_string: '2023-04-24T00:00:00.000Z', key: 1682294400000, doc_count: 0 }, - { key_as_string: '2023-04-25T00:00:00.000Z', key: 1682380800000, doc_count: 0 }, - { key_as_string: '2023-04-26T00:00:00.000Z', key: 1682467200000, doc_count: 0 }, - { key_as_string: '2023-04-27T00:00:00.000Z', key: 1682553600000, doc_count: 0 }, - { key_as_string: '2023-04-28T00:00:00.000Z', key: 1682640000000, doc_count: 0 }, - { key_as_string: '2023-04-29T00:00:00.000Z', key: 1682726400000, doc_count: 0 }, - { key_as_string: '2023-04-30T00:00:00.000Z', key: 1682812800000, doc_count: 0 }, - { key_as_string: '2023-05-01T00:00:00.000Z', key: 1682899200000, doc_count: 0 }, - { key_as_string: '2023-05-02T00:00:00.000Z', key: 1682985600000, doc_count: 0 }, - { key_as_string: '2023-05-03T00:00:00.000Z', key: 1683072000000, doc_count: 0 }, - { key_as_string: '2023-05-04T00:00:00.000Z', key: 1683158400000, doc_count: 0 }, - { key_as_string: '2023-05-05T00:00:00.000Z', key: 1683244800000, doc_count: 0 }, - { key_as_string: '2023-05-06T00:00:00.000Z', key: 1683331200000, doc_count: 0 }, - { key_as_string: '2023-05-07T00:00:00.000Z', key: 1683417600000, doc_count: 0 }, - { key_as_string: '2023-05-08T00:00:00.000Z', key: 1683504000000, doc_count: 0 }, - { key_as_string: '2023-05-09T00:00:00.000Z', key: 1683590400000, doc_count: 0 }, - { key_as_string: '2023-05-10T00:00:00.000Z', key: 1683676800000, doc_count: 32 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + { key_as_string: '2023-04-11T00:00:00.000Z', key: 1681171200000, doc_count: 0 }, + { key_as_string: '2023-04-12T00:00:00.000Z', key: 1681257600000, doc_count: 0 }, + { key_as_string: '2023-04-13T00:00:00.000Z', key: 1681344000000, doc_count: 0 }, + { key_as_string: '2023-04-14T00:00:00.000Z', key: 1681430400000, doc_count: 0 }, + { key_as_string: '2023-04-15T00:00:00.000Z', key: 1681516800000, doc_count: 0 }, + { key_as_string: '2023-04-16T00:00:00.000Z', key: 1681603200000, doc_count: 0 }, + { key_as_string: '2023-04-17T00:00:00.000Z', key: 1681689600000, doc_count: 0 }, + { key_as_string: '2023-04-18T00:00:00.000Z', key: 1681776000000, doc_count: 0 }, + { key_as_string: '2023-04-19T00:00:00.000Z', key: 1681862400000, doc_count: 0 }, + { key_as_string: '2023-04-20T00:00:00.000Z', key: 1681948800000, doc_count: 0 }, + { key_as_string: '2023-04-21T00:00:00.000Z', key: 1682035200000, doc_count: 0 }, + { key_as_string: '2023-04-22T00:00:00.000Z', key: 1682121600000, doc_count: 0 }, + { key_as_string: '2023-04-23T00:00:00.000Z', key: 1682208000000, doc_count: 0 }, + { key_as_string: '2023-04-24T00:00:00.000Z', key: 1682294400000, doc_count: 0 }, + { key_as_string: '2023-04-25T00:00:00.000Z', key: 1682380800000, doc_count: 0 }, + { key_as_string: '2023-04-26T00:00:00.000Z', key: 1682467200000, doc_count: 0 }, + { key_as_string: '2023-04-27T00:00:00.000Z', key: 1682553600000, doc_count: 0 }, + { key_as_string: '2023-04-28T00:00:00.000Z', key: 1682640000000, doc_count: 0 }, + { key_as_string: '2023-04-29T00:00:00.000Z', key: 1682726400000, doc_count: 0 }, + { key_as_string: '2023-04-30T00:00:00.000Z', key: 1682812800000, doc_count: 0 }, + { key_as_string: '2023-05-01T00:00:00.000Z', key: 1682899200000, doc_count: 0 }, + { key_as_string: '2023-05-02T00:00:00.000Z', key: 1682985600000, doc_count: 0 }, + { key_as_string: '2023-05-03T00:00:00.000Z', key: 1683072000000, doc_count: 0 }, + { key_as_string: '2023-05-04T00:00:00.000Z', key: 1683158400000, doc_count: 0 }, + { key_as_string: '2023-05-05T00:00:00.000Z', key: 1683244800000, doc_count: 0 }, + { key_as_string: '2023-05-06T00:00:00.000Z', key: 1683331200000, doc_count: 0 }, + { key_as_string: '2023-05-07T00:00:00.000Z', key: 1683417600000, doc_count: 0 }, + { key_as_string: '2023-05-08T00:00:00.000Z', key: 1683504000000, doc_count: 0 }, + { key_as_string: '2023-05-09T00:00:00.000Z', key: 1683590400000, doc_count: 0 }, + { key_as_string: '2023-05-10T00:00:00.000Z', key: 1683676800000, doc_count: 32 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); + const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -155,26 +155,24 @@ describe('useAlertsHistory', () => { it('calls http post including instanceId query', async () => { const controller = new AbortController(); const signal = controller.signal; - const mockedHttpPost = jest.fn(); - const http = { - post: mockedHttpPost.mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], + consumers: ['foo'], ruleId, dateRange: { from: start, to: end }, instanceId: 'instance-1', @@ -187,9 +185,10 @@ describe('useAlertsHistory', () => { await act(async () => { await waitFor(() => result.current.isSuccess); }); - expect(mockedHttpPost).toBeCalledWith('/internal/rac/alerts/find', { + + expect(mockServices.http.post).toBeCalledWith('/internal/rac/alerts/find', { body: - '{"size":0,"feature_ids":["apm"],"query":{"bool":{"must":[' + + '{"size":0,"rule_type_ids":["apm"],"consumers":["foo"],"query":{"bool":{"must":[' + '{"term":{"kibana.alert.rule.uuid":"cfd36e60-ef22-11ed-91eb-b7893acacfe2"}},' + '{"term":{"kibana.alert.instance.id":"instance-1"}},' + '{"range":{"kibana.alert.time_range":{"from":"2023-04-10T00:00:00.000Z","to":"2023-05-10T00:00:00.000Z"}}}]}},' + @@ -204,26 +203,23 @@ describe('useAlertsHistory', () => { it('calls http post without * instanceId query', async () => { const controller = new AbortController(); const signal = controller.signal; - const mockedHttpPost = jest.fn(); - const http = { - post: mockedHttpPost.mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, instanceId: '*', @@ -236,9 +232,10 @@ describe('useAlertsHistory', () => { await act(async () => { await waitFor(() => result.current.isSuccess); }); - expect(mockedHttpPost).toBeCalledWith('/internal/rac/alerts/find', { + + expect(mockServices.http.post).toBeCalledWith('/internal/rac/alerts/find', { body: - '{"size":0,"feature_ids":["apm"],"query":{"bool":{"must":[' + + '{"size":0,"rule_type_ids":["apm"],"query":{"bool":{"must":[' + '{"term":{"kibana.alert.rule.uuid":"cfd36e60-ef22-11ed-91eb-b7893acacfe2"}},' + '{"range":{"kibana.alert.time_range":{"from":"2023-04-10T00:00:00.000Z","to":"2023-05-10T00:00:00.000Z"}}}]}},' + '"aggs":{"histogramTriggeredAlerts":{"date_histogram":{"field":"kibana.alert.start","fixed_interval":"1d",' + diff --git a/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts b/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts index 193acb63f845b..d045fab2e635b 100644 --- a/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts +++ b/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts @@ -14,14 +14,14 @@ import { ALERT_START, ALERT_STATUS, ALERT_TIME_RANGE, - ValidFeatureId, } from '@kbn/rule-data-utils'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; import { useQuery } from '@tanstack/react-query'; export interface Props { http: HttpSetup | undefined; - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; ruleId: string; dateRange: { from: string; @@ -49,13 +49,15 @@ export const EMPTY_ALERTS_HISTORY = { }; export function useAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, ruleId, dateRange, http, instanceId, }: Props): UseAlertsHistory { - const enabled = !!featureIds.length; + const enabled = !!ruleTypeIds.length; + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['useAlertsHistory'], queryFn: async ({ signal }) => { @@ -63,7 +65,8 @@ export function useAlertsHistory({ throw new Error('Http client is missing'); } return fetchTriggeredAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, http, ruleId, dateRange, @@ -74,6 +77,7 @@ export function useAlertsHistory({ refetchOnWindowFocus: false, enabled, }); + return { data: isInitialLoading ? EMPTY_ALERTS_HISTORY : data ?? EMPTY_ALERTS_HISTORY, isLoading: enabled && (isInitialLoading || isLoading || isRefetching), @@ -101,14 +105,16 @@ interface AggsESResponse { } export async function fetchTriggeredAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, http, ruleId, dateRange, signal, instanceId, }: { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; http: HttpSetup; ruleId: string; dateRange: { @@ -123,7 +129,8 @@ export async function fetchTriggeredAlertsHistory({ signal, body: JSON.stringify({ size: 0, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query: { bool: { must: [ diff --git a/x-pack/packages/observability/alert_details/tsconfig.json b/x-pack/packages/observability/alert_details/tsconfig.json index a349651fdff7e..d1b4c3fb2ce23 100644 --- a/x-pack/packages/observability/alert_details/tsconfig.json +++ b/x-pack/packages/observability/alert_details/tsconfig.json @@ -17,9 +17,9 @@ ], "kbn_references": [ "@kbn/i18n", - "@kbn/core-http-browser", "@kbn/rule-data-utils", "@kbn/core", - "@kbn/rule-registry-plugin" + "@kbn/rule-registry-plugin", + "@kbn/core-http-browser-mocks" ] } diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index c2b1a0989c2ec..fdb059d971943 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -76,7 +76,6 @@ export const LogCategoriesResultContent: React.FC void; logCategory: LogCategory; - categoryDetailsServiceState: StateFrom; dependencies: LogCategoriesFlyoutDependencies; logsSource: ResolvedIndexNameLogsSourceConfiguration; documentFilters?: QueryDslQueryContainer[]; @@ -51,7 +55,6 @@ interface LogCategoryDetailsFlyoutProps { export const LogCategoryDetailsFlyout: React.FC = ({ onCloseFlyout, logCategory, - categoryDetailsServiceState, dependencies, logsSource, documentFilters, @@ -61,11 +64,19 @@ export const LogCategoryDetailsFlyout: React.FC = prefix: 'flyoutTitle', }); + const categoryFilter = useMemo(() => { + return createCategoryQuery(logsSource.messageField)(logCategory.terms); + }, [logCategory.terms, logsSource.messageField]); + + const documentAndCategoryFilters = useMemo(() => { + return [...(documentFilters ?? []), categoryFilter]; + }, [categoryFilter, documentFilters]); + const linkFilters = useMemo(() => { return [ ...(documentFilters ? documentFilters.map((filter) => ({ filter })) : []), { - filter: createCategoryQuery(logsSource.messageField)(logCategory.terms), + filter: categoryFilter, meta: { name: i18n.translate( 'xpack.observabilityLogsOverview.logCategoryDetailsFlyout.discoverLinkFilterName', @@ -79,7 +90,20 @@ export const LogCategoryDetailsFlyout: React.FC = }, }, ]; - }, [documentFilters, logCategory.terms, logsSource.messageField]); + }, [categoryFilter, documentFilters, logCategory.terms]); + + const filters = useMemo(() => { + return documentAndCategoryFilters.map((filter) => + buildCustomFilter( + logsSource.indexName, + filter, + false, + false, + 'Document filters', + FilterStateStore.APP_STATE + ) + ); + }, [documentAndCategoryFilters, logsSource.indexName]); return ( onCloseFlyout()} aria-labelledby={flyoutTitleId}> @@ -107,32 +131,12 @@ export const LogCategoryDetailsFlyout: React.FC = - - {categoryDetailsServiceState.matches({ hasCategory: 'fetchingDocuments' }) ? ( - - ) : categoryDetailsServiceState.matches({ hasCategory: 'error' }) ? ( - - ) : ( - - )} + + ); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index 6b43fa86fe49e..0101a2496415f 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -5,147 +5,45 @@ * 2.0. */ -import { EuiBasicTable, EuiBasicTableColumn, EuiSpacer, EuiText } from '@elastic/eui'; -import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; -import moment from 'moment'; -import type { SettingsStart } from '@kbn/core-ui-settings-browser'; -import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import { CoreStart } from '@kbn/core-lifecycle-browser'; -import { getLogLevelBadgeCell, LazySummaryColumn } from '@kbn/discover-contextual-components'; -import type { LogCategoryDocument } from '../../services/category_details_service/types'; -import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import React from 'react'; +import { LazySavedSearchComponent } from '@kbn/saved-search-component'; +import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; +import { Filter } from '@kbn/es-query'; +import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; export interface LogCategoryDocumentExamplesTableDependencies { - core: CoreStart; - uiSettings: SettingsStart; - fieldFormats: FieldFormatsStart; - share: SharePluginStart; + embeddable: EmbeddableStart; + dataViews: DataViewsContract; + searchSource: ISearchStartSearchSource; } export interface LogCategoryDocumentExamplesTableProps { dependencies: LogCategoryDocumentExamplesTableDependencies; - categoryDocuments: LogCategoryDocument[]; logsSource: ResolvedIndexNameLogsSourceConfiguration; + filters: Filter[]; } -const TimestampCell = ({ - dependencies, - timestamp, -}: { - dependencies: LogCategoryDocumentExamplesTableDependencies; - timestamp?: string | number; -}) => { - const dateFormat = useMemo( - () => dependencies.uiSettings.client.get('dateFormat'), - [dependencies.uiSettings.client] - ); - if (!timestamp) return null; - - if (dateFormat) { - return <>{moment(timestamp).format(dateFormat)}; - } else { - return <>{timestamp}; - } -}; - -const LogLevelBadgeCell = getLogLevelBadgeCell('log.level'); - export const LogCategoryDocumentExamplesTable: React.FC = ({ - categoryDocuments, dependencies, + filters, logsSource, }) => { - const columns: Array> = [ - { - field: 'row', - name: 'Timestamp', - width: '25%', - render: (row: any) => { - return ( - - ); - }, - }, - { - field: 'row', - name: 'Log level', - width: '10%', - render: (row: any) => { - return ( - {}} - closePopover={() => {}} - /> - ); - }, - }, - { - field: 'row', - name: 'Summary', - width: '65%', - render: (row: any) => { - return ( - {}} - closePopover={() => {}} - density={DataGridDensity.COMPACT} - rowHeight={ROWS_HEIGHT_OPTIONS.single} - shouldShowFieldHandler={() => false} - core={dependencies.core} - share={dependencies.share} - /> - ); - }, - }, - ]; return ( - <> - - {i18n.translate( - 'xpack.observabilityLogsOverview.logCategoryDocumentExamplesTable.documentCountText', - { - defaultMessage: 'Displaying the latest {documentsCount} documents.', - values: { - documentsCount: categoryDocuments.length, - }, - } - )} - - - - + ); }; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts index 958f717548600..40dc0d1eca122 100644 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts @@ -7,40 +7,24 @@ import { MachineImplementationsFrom, assign, setup } from 'xstate5'; import { LogCategory } from '../../types'; -import { getPlaceholderFor } from '../../utils/xstate5_utils'; -import { - CategoryDetailsServiceDependencies, - LogCategoryDocument, - LogCategoryDetailsParams, -} from './types'; -import { getCategoryDocuments } from './category_documents'; +import { CategoryDetailsServiceDependencies, LogCategoryDetailsParams } from './types'; export const categoryDetailsService = setup({ types: { input: {} as LogCategoryDetailsParams, - output: {} as { - categoryDocuments: LogCategoryDocument[] | null; - }, + output: {} as {}, context: {} as { parameters: LogCategoryDetailsParams; - error?: Error; expandedRowIndex: number | null; expandedCategory: LogCategory | null; - categoryDocuments: LogCategoryDocument[]; }, - events: {} as - | { - type: 'cancel'; - } - | { - type: 'setExpandedCategory'; - rowIndex: number | null; - category: LogCategory | null; - }, - }, - actors: { - getCategoryDocuments: getPlaceholderFor(getCategoryDocuments), + events: {} as { + type: 'setExpandedCategory'; + rowIndex: number | null; + category: LogCategory | null; + }, }, + actors: {}, actions: { storeCategory: assign( ({ context, event }, params: { category: LogCategory | null; rowIndex: number | null }) => ({ @@ -48,22 +32,10 @@ export const categoryDetailsService = setup({ expandedRowIndex: params.rowIndex, }) ), - storeDocuments: assign( - ({ context, event }, params: { categoryDocuments: LogCategoryDocument[] }) => ({ - categoryDocuments: params.categoryDocuments, - }) - ), - storeError: assign((_, params: { error: unknown }) => ({ - error: params.error instanceof Error ? params.error : new Error(String(params.error)), - })), }, guards: { hasCategory: (_guardArgs, params: { expandedCategory: LogCategory | null }) => params.expandedCategory !== null, - hasDocumentExamples: ( - _guardArgs, - params: { categoryDocuments: LogCategoryDocument[] | null } - ) => params.categoryDocuments !== null && params.categoryDocuments.length > 0, }, }).createMachine({ /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ @@ -71,7 +43,6 @@ export const categoryDetailsService = setup({ context: ({ input }) => ({ expandedCategory: null, expandedRowIndex: null, - categoryDocuments: [], parameters: input, }), initial: 'idle', @@ -79,38 +50,6 @@ export const categoryDetailsService = setup({ idle: { on: { setExpandedCategory: { - target: 'checkingCategoryState', - actions: [ - { - type: 'storeCategory', - params: ({ event }) => event, - }, - ], - }, - }, - }, - checkingCategoryState: { - always: [ - { - guard: { - type: 'hasCategory', - params: ({ event, context }) => { - return { - expandedCategory: context.expandedCategory, - }; - }, - }, - target: '#hasCategory.fetchingDocuments', - }, - { target: 'idle' }, - ], - }, - hasCategory: { - id: 'hasCategory', - initial: 'fetchingDocuments', - on: { - setExpandedCategory: { - target: 'checkingCategoryState', actions: [ { type: 'storeCategory', @@ -119,73 +58,13 @@ export const categoryDetailsService = setup({ ], }, }, - states: { - fetchingDocuments: { - invoke: { - src: 'getCategoryDocuments', - id: 'fetchCategoryDocumentExamples', - input: ({ context }) => ({ - ...context.parameters, - categoryTerms: context.expandedCategory!.terms, - }), - onDone: [ - { - guard: { - type: 'hasDocumentExamples', - params: ({ event }) => { - return event.output; - }, - }, - target: 'hasData', - actions: [ - { - type: 'storeDocuments', - params: ({ event }) => { - return event.output; - }, - }, - ], - }, - { - target: 'noData', - actions: [ - { - type: 'storeDocuments', - params: ({ event }) => { - return { categoryDocuments: [] }; - }, - }, - ], - }, - ], - onError: { - target: 'error', - actions: [ - { - type: 'storeError', - params: ({ event }) => ({ error: event.error }), - }, - ], - }, - }, - }, - hasData: {}, - noData: {}, - error: {}, - }, }, }, - output: ({ context }) => ({ - categoryDocuments: context.categoryDocuments, - }), + output: ({ context }) => ({}), }); export const createCategoryDetailsServiceImplementations = ({ search, }: CategoryDetailsServiceDependencies): MachineImplementationsFrom< typeof categoryDetailsService -> => ({ - actors: { - getCategoryDocuments: getCategoryDocuments({ search }), - }, -}); +> => ({}); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts deleted file mode 100644 index b513fa79fc686..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts +++ /dev/null @@ -1,63 +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 { ISearchGeneric } from '@kbn/search-types'; -import { fromPromise } from 'xstate5'; -import { lastValueFrom } from 'rxjs'; -import { flattenHit } from '@kbn/data-service'; -import { LogCategoryDocument, LogCategoryDocumentsParams } from './types'; -import { createGetLogCategoryDocumentsRequestParams } from './queries'; - -export const getCategoryDocuments = ({ search }: { search: ISearchGeneric }) => - fromPromise< - { - categoryDocuments: LogCategoryDocument[]; - }, - LogCategoryDocumentsParams - >( - async ({ - input: { - index, - endTimestamp, - startTimestamp, - timeField, - messageField, - categoryTerms, - additionalFilters = [], - dataView, - }, - signal, - }) => { - const requestParams = createGetLogCategoryDocumentsRequestParams({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - additionalFilters, - categoryTerms, - }); - - const { rawResponse } = await lastValueFrom( - search({ params: requestParams }, { abortSignal: signal }) - ); - - const categoryDocuments: LogCategoryDocument[] = - rawResponse.hits?.hits.map((hit) => { - return { - row: { - raw: hit._source, - flattened: flattenHit(hit, dataView), - }, - }; - }) ?? []; - - return { - categoryDocuments, - }; - } - ); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts deleted file mode 100644 index cd1053077c334..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts +++ /dev/null @@ -1,58 +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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { createCategoryQuery } from '../categorize_logs_service/queries'; - -export const createGetLogCategoryDocumentsRequestParams = ({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - additionalFilters = [], - categoryTerms = '', - documentCount = 20, -}: { - startTimestamp: string; - endTimestamp: string; - index: string; - timeField: string; - messageField: string; - additionalFilters?: QueryDslQueryContainer[]; - categoryTerms?: string; - documentCount?: number; -}) => { - return { - index, - size: documentCount, - track_total_hits: false, - sort: [{ [timeField]: { order: 'desc' } }], - query: { - bool: { - filter: [ - { - exists: { - field: messageField, - }, - }, - { - range: { - [timeField]: { - gte: startTimestamp, - lte: endTimestamp, - format: 'strict_date_time', - }, - }, - }, - createCategoryQuery(messageField)(categoryTerms), - ...additionalFilters, - ], - }, - }, - }; -}; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts index 72369275578e3..9c3327632055a 100644 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts @@ -8,11 +8,6 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { ISearchGeneric } from '@kbn/search-types'; import { type DataView } from '@kbn/data-views-plugin/common'; -import type { DataTableRecord } from '@kbn/discover-utils'; - -export interface LogCategoryDocument { - row: Pick; -} export interface LogCategoryDetailsParams { additionalFilters: QueryDslQueryContainer[]; @@ -27,5 +22,3 @@ export interface LogCategoryDetailsParams { export interface CategoryDetailsServiceDependencies { search: ISearchGeneric; } - -export type LogCategoryDocumentsParams = LogCategoryDetailsParams & { categoryTerms: string }; diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 29595ce0162fe..610ef8cc0126e 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -34,12 +34,9 @@ "@kbn/es-query", "@kbn/router-utils", "@kbn/share-plugin", - "@kbn/field-formats-plugin", - "@kbn/data-service", - "@kbn/discover-utils", "@kbn/discover-plugin", - "@kbn/unified-data-table", - "@kbn/discover-contextual-components", - "@kbn/core-lifecycle-browser", + "@kbn/embeddable-plugin", + "@kbn/data-plugin", + "@kbn/saved-search-component", ] } diff --git a/x-pack/packages/security-solution/distribution_bar/README.md b/x-pack/packages/security-solution/distribution_bar/README.md new file mode 100644 index 0000000000000..51edea2dd1846 --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/README.md @@ -0,0 +1,10 @@ +# Security Solution's Distribution Bar + +The DistributionBar component visually represents data distribution, such as critical, high, medium, and low alerts. + +## Storybook + +General look of the component can be checked visually running the following storybook: +`yarn storybook security_solution_packages` + +Note that all the interactions are mocked. \ No newline at end of file diff --git a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx index f2d1099d17c50..0942cace23267 100644 --- a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx +++ b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx @@ -12,7 +12,15 @@ import { css } from '@emotion/react'; /** DistributionBar component props */ export interface DistributionBarProps { /** distribution data points */ - stats: Array<{ key: string; count: number; color: string; label?: React.ReactNode }>; + stats: Array<{ + key: string; + count: number; + color: string; + label?: React.ReactNode; + isCurrentFilter?: boolean; + filter?: () => void; + reset?: (event: React.MouseEvent) => void; + }>; /** hide the label above the bar at first render */ hideLastTooltip?: boolean; /** data-test-subj used for querying the component in tests */ @@ -36,6 +44,7 @@ const useStyles = () => { position: relative; border-radius: 2px; height: 5px; + min-width: 10px; // prevents bar from shrinking too small `, empty: css` background-color: ${euiTheme.colors.lightShade}; @@ -155,7 +164,19 @@ export const DistributionBar: React.FC = React.memo(functi const prettyNumber = numeral(stat.count).format('0,0a'); return ( -
        +
        { + if (event.key === 'Enter' || event.key === ' ') { + stat.filter?.(); + } + }} + tabIndex={0} + role="button" + >
        = React.memo(functi {stat.label ? stat.label : stat.key} + {stat.isCurrentFilter ? ( + + + + ) : undefined} diff --git a/x-pack/packages/security-solution/features/src/security/kibana_features.ts b/x-pack/packages/security-solution/features/src/security/kibana_features.ts index 2fb6b11988797..458b8f6fd1f1f 100644 --- a/x-pack/packages/security-solution/features/src/security/kibana_features.ts +++ b/x-pack/packages/security-solution/features/src/security/kibana_features.ts @@ -41,6 +41,11 @@ const SECURITY_RULE_TYPES = [ NEW_TERMS_RULE_TYPE_ID, ]; +const alertingFeatures = SECURITY_RULE_TYPES.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [SERVER_APP_ID], +})); + export const getSecurityBaseKibanaFeature = ({ savedObjects, }: SecurityFeatureParams): BaseKibanaFeatureConfig => ({ @@ -59,7 +64,7 @@ export const getSecurityBaseKibanaFeature = ({ management: { insightsAndAlerting: ['triggersActions'], }, - alerting: SECURITY_RULE_TYPES, + alerting: alertingFeatures, description: i18n.translate( 'securitySolutionPackages.features.featureRegistry.securityGroupDescription', { @@ -87,12 +92,8 @@ export const getSecurityBaseKibanaFeature = ({ read: [], }, alerting: { - rule: { - all: SECURITY_RULE_TYPES, - }, - alert: { - all: SECURITY_RULE_TYPES, - }, + rule: { all: alertingFeatures }, + alert: { all: alertingFeatures }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -109,10 +110,10 @@ export const getSecurityBaseKibanaFeature = ({ }, alerting: { rule: { - read: SECURITY_RULE_TYPES, + read: alertingFeatures, }, alert: { - all: SECURITY_RULE_TYPES, + all: alertingFeatures, }, }, management: { diff --git a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts index f5af4cd05ad24..06d6709ddcb42 100644 --- a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts +++ b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts @@ -39,19 +39,19 @@ export const SolutionSideNavPanelStyles = ( // bottom inset to match timeline bar top shadow inset 0 -6px ${euiTheme.size.xs} -${euiTheme.size.xs} rgb(0 0 0 / 15%); `} +`; - .solutionSideNavPanelLink { - &:focus-within { - background-color: transparent; - a { - text-decoration: auto; - } +export const SolutionSideNavPanelItemStyles = (euiTheme: EuiThemeComputed<{}>) => css` + &:focus-within { + background-color: transparent; + a { + text-decoration: auto; } - &:hover { - background-color: ${transparentize(euiTheme.colors.primary, 0.1)}; - a { - text-decoration: underline; - } + } + &:hover { + background-color: ${transparentize(euiTheme.colors.lightShade, 0.5)}; + a { + text-decoration: underline; } } `; diff --git a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx index 248121872018b..38cce27db1c44 100644 --- a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx +++ b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx @@ -48,6 +48,7 @@ import { SolutionSideNavPanelLinksGroupStyles, panelClassName, accordionButtonClassName, + SolutionSideNavPanelItemStyles, } from './solution_side_nav_panel.styles'; export interface SolutionSideNavPanelContentProps { @@ -354,7 +355,8 @@ interface SolutionSideNavPanelItemProps { const SolutionSideNavPanelItem: React.FC = React.memo( function SolutionSideNavPanelItem({ item, onClose }) { const { tracker } = useTelemetryContext(); - const panelLinkClassNames = classNames('solutionSideNavPanelLink'); + const { euiTheme } = useEuiTheme(); + const panelLinkClassNames = classNames(SolutionSideNavPanelItemStyles(euiTheme)); const { id, href, onClick, iconType, openInNewTab } = item; const onClickHandler = useCallback( (ev) => { diff --git a/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts b/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts index 1db1030da510a..8f3d48a91005c 100644 --- a/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts +++ b/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts @@ -51,21 +51,3 @@ describe('#get', () => { ); }); }); - -test('#isValid', () => { - const alertingActions = new AlertingActions(); - expect(alertingActions.isValid('alerting:foo-ruleType/consumer/alertingType/bar-operation')).toBe( - true - ); - - expect( - alertingActions.isValid('api:alerting:foo-ruleType/consumer/alertingType/bar-operation') - ).toBe(false); - expect(alertingActions.isValid('api:foo-ruleType/consumer/alertingType/bar-operation')).toBe( - false - ); - - expect(alertingActions.isValid('alerting_foo-ruleType/consumer/alertingType/bar-operation')).toBe( - false - ); -}); diff --git a/x-pack/packages/security/authorization_core/src/actions/alerting.ts b/x-pack/packages/security/authorization_core/src/actions/alerting.ts index 18abac73ef8b7..c1de9a1c65d21 100644 --- a/x-pack/packages/security/authorization_core/src/actions/alerting.ts +++ b/x-pack/packages/security/authorization_core/src/actions/alerting.ts @@ -40,12 +40,4 @@ export class AlertingActions implements AlertingActionsType { return `${this.prefix}${ruleTypeId}/${consumer}/${alertingEntity}/${operation}`; } - - /** - * Checks if the action is a valid alerting action. - * @param action The action string to check. - */ - public isValid(action: string) { - return action.startsWith(this.prefix); - } } diff --git a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts index db4aae642a56f..c5af930cce4f5 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts @@ -28,7 +28,6 @@ describe(`feature_privilege_builder`, () => { read: [], }, }, - savedObject: { all: [], read: [], @@ -59,10 +58,9 @@ describe(`feature_privilege_builder`, () => { alerting: { rule: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -83,15 +81,15 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", ] `); }); @@ -104,10 +102,9 @@ describe(`feature_privilege_builder`, () => { alerting: { alert: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -128,10 +125,10 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -144,14 +141,13 @@ describe(`feature_privilege_builder`, () => { alerting: { rule: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, alert: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -172,19 +168,19 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -196,7 +192,7 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, @@ -221,34 +217,34 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", ] `); }); @@ -260,11 +256,10 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, - savedObject: { all: [], read: [], @@ -285,11 +280,11 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", ] `); }); @@ -301,15 +296,14 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, alert: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, - savedObject: { all: [], read: [], @@ -330,39 +324,39 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", ] `); }); @@ -374,11 +368,10 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -399,43 +392,43 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:readonly-alert-type/my-feature/rule/get", - "alerting:readonly-alert-type/my-feature/rule/getRuleState", - "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", - "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", - "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", - "alerting:readonly-alert-type/my-feature/rule/find", - "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:readonly-alert-type/my-feature/rule/getBackfill", - "alerting:readonly-alert-type/my-feature/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:readonly-alert-type/my-consumer/rule/get", + "alerting:readonly-alert-type/my-consumer/rule/getRuleState", + "alerting:readonly-alert-type/my-consumer/rule/getAlertSummary", + "alerting:readonly-alert-type/my-consumer/rule/getExecutionLog", + "alerting:readonly-alert-type/my-consumer/rule/getActionErrorLog", + "alerting:readonly-alert-type/my-consumer/rule/find", + "alerting:readonly-alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type/my-consumer/rule/getBackfill", + "alerting:readonly-alert-type/my-consumer/rule/findBackfill", ] `); }); @@ -447,8 +440,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, @@ -472,15 +465,15 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", - "alerting:readonly-alert-type/my-feature/alert/get", - "alerting:readonly-alert-type/my-feature/alert/find", - "alerting:readonly-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:readonly-alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", + "alerting:readonly-alert-type/my-consumer/alert/get", + "alerting:readonly-alert-type/my-consumer/alert/find", + "alerting:readonly-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:readonly-alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -492,12 +485,128 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], + }, + alert: { + all: [{ ruleTypeId: 'another-alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:readonly-alert-type/my-consumer/rule/get", + "alerting:readonly-alert-type/my-consumer/rule/getRuleState", + "alerting:readonly-alert-type/my-consumer/rule/getAlertSummary", + "alerting:readonly-alert-type/my-consumer/rule/getExecutionLog", + "alerting:readonly-alert-type/my-consumer/rule/getActionErrorLog", + "alerting:readonly-alert-type/my-consumer/rule/find", + "alerting:readonly-alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type/my-consumer/rule/getBackfill", + "alerting:readonly-alert-type/my-consumer/rule/findBackfill", + "alerting:another-alert-type/my-consumer/alert/get", + "alerting:another-alert-type/my-consumer/alert/find", + "alerting:another-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type/my-consumer/alert/getAlertSummary", + "alerting:another-alert-type/my-consumer/alert/update", + "alerting:readonly-alert-type/my-consumer/alert/get", + "alerting:readonly-alert-type/my-consumer/alert/find", + "alerting:readonly-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:readonly-alert-type/my-consumer/alert/getAlertSummary", + ] + `); + }); + + test('handles multiple rule types and consumers correctly', () => { + const actions = new Actions(); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: [ + { ruleTypeId: 'alert-type-1', consumers: ['my-consumer-1', 'my-consumer-2'] }, + { ruleTypeId: 'alert-type-2', consumers: ['my-consumer-3'] }, + ], + read: [ + { + ruleTypeId: 'readonly-alert-type-1', + consumers: ['my-read-consumer-1', 'my-read-consumer-2'], + }, + { + ruleTypeId: 'readonly-alert-type-2', + consumers: ['my-read-consumer-3', 'my-read-consumer-4'], + }, + ], }, alert: { - all: ['another-alert-type'], - read: ['readonly-alert-type'], + all: [ + { + ruleTypeId: 'another-alert-type-1', + consumers: ['my-consumer-another-1', 'my-consumer-another-2'], + }, + { + ruleTypeId: 'another-alert-type-2', + consumers: ['my-consumer-another-3', 'my-consumer-another-1'], + }, + ], + read: [ + { + ruleTypeId: 'readonly-another-alert-type-1', + consumers: ['my-read-other-consumer-1', 'my-read-other-consumer-2'], + }, + { + ruleTypeId: 'readonly-another-alert-type-2', + consumers: ['my-read-other-consumer-3', 'my-read-other-consumer-4'], + }, + ], }, }, @@ -521,52 +630,162 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:readonly-alert-type/my-feature/rule/get", - "alerting:readonly-alert-type/my-feature/rule/getRuleState", - "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", - "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", - "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", - "alerting:readonly-alert-type/my-feature/rule/find", - "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:readonly-alert-type/my-feature/rule/getBackfill", - "alerting:readonly-alert-type/my-feature/rule/findBackfill", - "alerting:another-alert-type/my-feature/alert/get", - "alerting:another-alert-type/my-feature/alert/find", - "alerting:another-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:another-alert-type/my-feature/alert/getAlertSummary", - "alerting:another-alert-type/my-feature/alert/update", - "alerting:readonly-alert-type/my-feature/alert/get", - "alerting:readonly-alert-type/my-feature/alert/find", - "alerting:readonly-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:readonly-alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type-1/my-consumer-1/rule/get", + "alerting:alert-type-1/my-consumer-1/rule/getRuleState", + "alerting:alert-type-1/my-consumer-1/rule/getAlertSummary", + "alerting:alert-type-1/my-consumer-1/rule/getExecutionLog", + "alerting:alert-type-1/my-consumer-1/rule/getActionErrorLog", + "alerting:alert-type-1/my-consumer-1/rule/find", + "alerting:alert-type-1/my-consumer-1/rule/getRuleExecutionKPI", + "alerting:alert-type-1/my-consumer-1/rule/getBackfill", + "alerting:alert-type-1/my-consumer-1/rule/findBackfill", + "alerting:alert-type-1/my-consumer-1/rule/create", + "alerting:alert-type-1/my-consumer-1/rule/delete", + "alerting:alert-type-1/my-consumer-1/rule/update", + "alerting:alert-type-1/my-consumer-1/rule/updateApiKey", + "alerting:alert-type-1/my-consumer-1/rule/enable", + "alerting:alert-type-1/my-consumer-1/rule/disable", + "alerting:alert-type-1/my-consumer-1/rule/muteAll", + "alerting:alert-type-1/my-consumer-1/rule/unmuteAll", + "alerting:alert-type-1/my-consumer-1/rule/muteAlert", + "alerting:alert-type-1/my-consumer-1/rule/unmuteAlert", + "alerting:alert-type-1/my-consumer-1/rule/snooze", + "alerting:alert-type-1/my-consumer-1/rule/bulkEdit", + "alerting:alert-type-1/my-consumer-1/rule/bulkDelete", + "alerting:alert-type-1/my-consumer-1/rule/bulkEnable", + "alerting:alert-type-1/my-consumer-1/rule/bulkDisable", + "alerting:alert-type-1/my-consumer-1/rule/unsnooze", + "alerting:alert-type-1/my-consumer-1/rule/runSoon", + "alerting:alert-type-1/my-consumer-1/rule/scheduleBackfill", + "alerting:alert-type-1/my-consumer-1/rule/deleteBackfill", + "alerting:alert-type-1/my-consumer-2/rule/get", + "alerting:alert-type-1/my-consumer-2/rule/getRuleState", + "alerting:alert-type-1/my-consumer-2/rule/getAlertSummary", + "alerting:alert-type-1/my-consumer-2/rule/getExecutionLog", + "alerting:alert-type-1/my-consumer-2/rule/getActionErrorLog", + "alerting:alert-type-1/my-consumer-2/rule/find", + "alerting:alert-type-1/my-consumer-2/rule/getRuleExecutionKPI", + "alerting:alert-type-1/my-consumer-2/rule/getBackfill", + "alerting:alert-type-1/my-consumer-2/rule/findBackfill", + "alerting:alert-type-1/my-consumer-2/rule/create", + "alerting:alert-type-1/my-consumer-2/rule/delete", + "alerting:alert-type-1/my-consumer-2/rule/update", + "alerting:alert-type-1/my-consumer-2/rule/updateApiKey", + "alerting:alert-type-1/my-consumer-2/rule/enable", + "alerting:alert-type-1/my-consumer-2/rule/disable", + "alerting:alert-type-1/my-consumer-2/rule/muteAll", + "alerting:alert-type-1/my-consumer-2/rule/unmuteAll", + "alerting:alert-type-1/my-consumer-2/rule/muteAlert", + "alerting:alert-type-1/my-consumer-2/rule/unmuteAlert", + "alerting:alert-type-1/my-consumer-2/rule/snooze", + "alerting:alert-type-1/my-consumer-2/rule/bulkEdit", + "alerting:alert-type-1/my-consumer-2/rule/bulkDelete", + "alerting:alert-type-1/my-consumer-2/rule/bulkEnable", + "alerting:alert-type-1/my-consumer-2/rule/bulkDisable", + "alerting:alert-type-1/my-consumer-2/rule/unsnooze", + "alerting:alert-type-1/my-consumer-2/rule/runSoon", + "alerting:alert-type-1/my-consumer-2/rule/scheduleBackfill", + "alerting:alert-type-1/my-consumer-2/rule/deleteBackfill", + "alerting:alert-type-2/my-consumer-3/rule/get", + "alerting:alert-type-2/my-consumer-3/rule/getRuleState", + "alerting:alert-type-2/my-consumer-3/rule/getAlertSummary", + "alerting:alert-type-2/my-consumer-3/rule/getExecutionLog", + "alerting:alert-type-2/my-consumer-3/rule/getActionErrorLog", + "alerting:alert-type-2/my-consumer-3/rule/find", + "alerting:alert-type-2/my-consumer-3/rule/getRuleExecutionKPI", + "alerting:alert-type-2/my-consumer-3/rule/getBackfill", + "alerting:alert-type-2/my-consumer-3/rule/findBackfill", + "alerting:alert-type-2/my-consumer-3/rule/create", + "alerting:alert-type-2/my-consumer-3/rule/delete", + "alerting:alert-type-2/my-consumer-3/rule/update", + "alerting:alert-type-2/my-consumer-3/rule/updateApiKey", + "alerting:alert-type-2/my-consumer-3/rule/enable", + "alerting:alert-type-2/my-consumer-3/rule/disable", + "alerting:alert-type-2/my-consumer-3/rule/muteAll", + "alerting:alert-type-2/my-consumer-3/rule/unmuteAll", + "alerting:alert-type-2/my-consumer-3/rule/muteAlert", + "alerting:alert-type-2/my-consumer-3/rule/unmuteAlert", + "alerting:alert-type-2/my-consumer-3/rule/snooze", + "alerting:alert-type-2/my-consumer-3/rule/bulkEdit", + "alerting:alert-type-2/my-consumer-3/rule/bulkDelete", + "alerting:alert-type-2/my-consumer-3/rule/bulkEnable", + "alerting:alert-type-2/my-consumer-3/rule/bulkDisable", + "alerting:alert-type-2/my-consumer-3/rule/unsnooze", + "alerting:alert-type-2/my-consumer-3/rule/runSoon", + "alerting:alert-type-2/my-consumer-3/rule/scheduleBackfill", + "alerting:alert-type-2/my-consumer-3/rule/deleteBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/get", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getRuleState", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getAlertSummary", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getExecutionLog", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getActionErrorLog", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/find", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/findBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/get", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getRuleState", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getAlertSummary", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getExecutionLog", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getActionErrorLog", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/find", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/findBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/get", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getRuleState", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getAlertSummary", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getExecutionLog", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getActionErrorLog", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/find", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/findBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/get", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getRuleState", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getAlertSummary", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getExecutionLog", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getActionErrorLog", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/find", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/findBackfill", + "alerting:another-alert-type-1/my-consumer-another-1/alert/get", + "alerting:another-alert-type-1/my-consumer-another-1/alert/find", + "alerting:another-alert-type-1/my-consumer-another-1/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-1/my-consumer-another-1/alert/getAlertSummary", + "alerting:another-alert-type-1/my-consumer-another-1/alert/update", + "alerting:another-alert-type-1/my-consumer-another-2/alert/get", + "alerting:another-alert-type-1/my-consumer-another-2/alert/find", + "alerting:another-alert-type-1/my-consumer-another-2/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-1/my-consumer-another-2/alert/getAlertSummary", + "alerting:another-alert-type-1/my-consumer-another-2/alert/update", + "alerting:another-alert-type-2/my-consumer-another-3/alert/get", + "alerting:another-alert-type-2/my-consumer-another-3/alert/find", + "alerting:another-alert-type-2/my-consumer-another-3/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-2/my-consumer-another-3/alert/getAlertSummary", + "alerting:another-alert-type-2/my-consumer-another-3/alert/update", + "alerting:another-alert-type-2/my-consumer-another-1/alert/get", + "alerting:another-alert-type-2/my-consumer-another-1/alert/find", + "alerting:another-alert-type-2/my-consumer-another-1/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-2/my-consumer-another-1/alert/getAlertSummary", + "alerting:another-alert-type-2/my-consumer-another-1/alert/update", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/get", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/find", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/getAlertSummary", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/get", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/find", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/getAlertSummary", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/get", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/find", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/getAlertSummary", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/get", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/find", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/getAlertSummary", ] `); }); diff --git a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts index c0b7fa2ea8ab7..65c330b94c462 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts @@ -7,6 +7,7 @@ import { get, uniq } from 'lodash'; +import type { AlertingKibanaPrivilege } from '@kbn/features-plugin/common/alerting_kibana_privilege'; import type { FeatureKibanaPrivileges, KibanaFeature } from '@kbn/features-plugin/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; @@ -67,13 +68,14 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder ): string[] { const getAlertingPrivilege = ( operations: string[], - privilegedTypes: readonly string[], - alertingEntity: string, - consumer: string + privileges: AlertingKibanaPrivilege, + alertingEntity: string ) => - privilegedTypes.flatMap((type) => - operations.map((operation) => - this.actions.alerting.get(type, consumer, alertingEntity, operation) + privileges.flatMap(({ ruleTypeId, consumers }) => + consumers.flatMap((consumer) => + operations.map((operation) => + this.actions.alerting.get(ruleTypeId, consumer, alertingEntity, operation) + ) ) ); @@ -82,8 +84,8 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder const read = get(privilegeDefinition.alerting, `${entity}.read`) ?? []; return uniq([ - ...getAlertingPrivilege(allOperations[entity], all, entity, feature.id), - ...getAlertingPrivilege(readOperations[entity], read, entity, feature.id), + ...getAlertingPrivilege(allOperations[entity], all, entity), + ...getAlertingPrivilege(readOperations[entity], read, entity), ]); }; diff --git a/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts b/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts index 6af21d5357a72..22fb86f601b3a 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts @@ -481,7 +481,7 @@ describe('features', () => { name: 'Feature Alpha', app: [], category: { id: 'alpha', label: 'alpha' }, - alerting: ['rule-type-1'], + alerting: [{ ruleTypeId: 'rule-type-1', consumers: ['alpha'] }], privileges: { all: { savedObject: { @@ -491,7 +491,7 @@ describe('features', () => { ui: ['all-alpha-ui'], app: ['all-alpha-app'], api: ['all-alpha-api'], - alerting: { rule: { all: ['rule-type-1'] } }, + alerting: { rule: { all: [{ ruleTypeId: 'rule-type-1', consumers: ['alpha'] }] } }, replacedBy: [{ feature: 'beta', privileges: ['all'] }], }, read: { @@ -514,7 +514,7 @@ describe('features', () => { name: 'Feature Beta', app: [], category: { id: 'beta', label: 'beta' }, - alerting: ['rule-type-1'], + alerting: [{ ruleTypeId: 'rule-type-1', consumers: ['beta'] }], privileges: { all: { savedObject: { @@ -524,7 +524,7 @@ describe('features', () => { ui: ['all-beta-ui'], app: ['all-beta-app'], api: ['all-beta-api'], - alerting: { rule: { all: ['rule-type-1'] } }, + alerting: { rule: { all: [{ ruleTypeId: 'rule-type-1', consumers: ['beta'] }] } }, }, read: { savedObject: { @@ -604,13 +604,8 @@ describe('features', () => { ...alertingOperations.map((operation) => actions.alerting.get('rule-type-1', 'alpha', 'rule', operation) ), - // To maintain compatibility with the new UI capabilities and new alerting entities that are - // feature specific: all.replacedBy: [{ feature: 'beta', privileges: ['all'] }] actions.ui.get('navLinks', 'all-beta-app'), actions.ui.get('beta', 'all-beta-ui'), - ...alertingOperations.map((operation) => - actions.alerting.get('rule-type-1', 'beta', 'rule', operation) - ), ]; const expectedReadPrivileges = [ diff --git a/x-pack/packages/security/authorization_core/src/privileges/privileges.ts b/x-pack/packages/security/authorization_core/src/privileges/privileges.ts index b81eaba5fa54d..f266b2b9a7085 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/privileges.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/privileges.ts @@ -94,17 +94,15 @@ export function privilegesFactory( // If a privilege is configured with `replacedBy`, it's part of the deprecated feature and // should be complemented with the subset of actions from the referenced privileges to // maintain backward compatibility. Namely, deprecated privileges should grant the same UI - // capabilities and alerting actions as the privileges that replace them, so that the - // client-side code can safely use only non-deprecated UI capabilities and users can still - // access previously created alerting rules and alerts. + // capabilities as the privileges that replace them, so that the client-side code can safely + // use only non-deprecated UI capabilities. const replacedBy = getReplacedByForPrivilege(privilegeId, privilege); if (replacedBy) { composablePrivileges.push({ featureId: feature.id, privilegeId, references: replacedBy, - actionsFilter: (action) => - actions.ui.isValid(action) || actions.alerting.isValid(action), + actionsFilter: (action) => actions.ui.isValid(action), }); } }; diff --git a/x-pack/packages/security/form_components/src/form_changes.test.tsx b/x-pack/packages/security/form_components/src/form_changes.test.tsx index 3223bb727ddfb..1ce5e4d1e07de 100644 --- a/x-pack/packages/security/form_components/src/form_changes.test.tsx +++ b/x-pack/packages/security/form_components/src/form_changes.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import type { RevertFunction } from './form_changes'; import { useFormChanges } from './form_changes'; diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts index 433e3850cae2a..9834765487a80 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts @@ -22,7 +22,6 @@ const createActionsClientMock = () => { getBulk: jest.fn(), getOAuthAccessToken: jest.fn(), execute: jest.fn(), - ephemeralEnqueuedExecution: jest.fn(), bulkEnqueueExecution: jest.fn(), listTypes: jest.fn(), isActionTypeEnabled: jest.fn(), diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts index 99bcbf15ecfb9..b977f8fb97cd3 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts @@ -79,7 +79,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -138,7 +137,6 @@ beforeEach(() => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -613,7 +611,6 @@ describe('create()', () => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -739,7 +736,6 @@ describe('create()', () => { ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -801,7 +797,6 @@ describe('create()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -862,7 +857,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -899,7 +893,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -956,7 +949,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -999,7 +991,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1121,7 +1112,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1165,7 +1155,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1199,7 +1188,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1270,7 +1258,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1408,7 +1395,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1503,7 +1489,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1577,7 +1562,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1662,7 +1646,6 @@ describe('getOAuthAccessToken()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2097,7 +2080,6 @@ describe('delete()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2133,7 +2115,6 @@ describe('delete()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2653,7 +2634,6 @@ describe('update()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2696,7 +2676,6 @@ describe('update()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2782,7 +2761,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2845,7 +2823,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2907,7 +2884,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3180,7 +3156,6 @@ describe('isPreconfigured()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3230,7 +3205,6 @@ describe('isPreconfigured()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3282,7 +3256,6 @@ describe('isSystemAction()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3332,7 +3305,6 @@ describe('isSystemAction()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index 5c563fbd6aa82..e39cf8712894f 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -18,7 +18,6 @@ import { Logger, } from '@kbn/core/server'; import { AuditLogger } from '@kbn/security-plugin/server'; -import { RunNowResult } from '@kbn/task-manager-plugin/server'; import { IEventLogClient } from '@kbn/event-log-plugin/server'; import { KueryNode } from '@kbn/es-query'; import { Connector, ConnectorWithExtraFindData } from '../application/connector/types'; @@ -46,7 +45,6 @@ import { } from '../types'; import { PreconfiguredActionDisabledModificationError } from '../lib/errors/preconfigured_action_disabled_modification'; import { - ExecutionEnqueuer, ExecuteOptions as EnqueueExecutionOptions, BulkExecutionEnqueuer, ExecutionResponse, @@ -92,7 +90,6 @@ export interface ConstructorOptions { unsecuredSavedObjectsClient: SavedObjectsClientContract; inMemoryConnectors: InMemoryConnector[]; actionExecutor: ActionExecutorContract; - ephemeralExecutionEnqueuer: ExecutionEnqueuer; bulkExecutionEnqueuer: BulkExecutionEnqueuer; request: KibanaRequest; authorization: ActionsAuthorization; @@ -112,7 +109,6 @@ export interface ActionsClientContext { actionExecutor: ActionExecutorContract; request: KibanaRequest; authorization: ActionsAuthorization; - ephemeralExecutionEnqueuer: ExecutionEnqueuer; bulkExecutionEnqueuer: BulkExecutionEnqueuer; auditLogger?: AuditLogger; usageCounter?: UsageCounter; @@ -131,7 +127,6 @@ export class ActionsClient { unsecuredSavedObjectsClient, inMemoryConnectors, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization, @@ -148,7 +143,6 @@ export class ActionsClient { kibanaIndices, inMemoryConnectors, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization, @@ -504,18 +498,6 @@ export class ActionsClient { return this.context.bulkExecutionEnqueuer(this.context.unsecuredSavedObjectsClient, options); } - public async ephemeralEnqueuedExecution(options: EnqueueExecutionOptions): Promise { - await this.context.authorization.ensureAuthorized({ - operation: 'execute', - actionTypeId: options.actionTypeId, - }); - - return this.context.ephemeralExecutionEnqueuer( - this.context.unsecuredSavedObjectsClient, - options - ); - } - public async listTypes({ featureId, includeSystemActionTypes = false, diff --git a/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts index 7a1a0fb5e3d91..303254a66ea19 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts @@ -38,7 +38,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -131,7 +130,6 @@ beforeEach(() => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts index 0f86a8e582e34..5ff37776cf2dc 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts @@ -52,7 +52,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -78,7 +77,6 @@ describe('getAll()', () => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -134,7 +132,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -279,7 +276,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -382,7 +378,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -487,7 +482,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -579,7 +573,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -613,7 +606,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -690,7 +682,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts b/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts index 9ff5e05d45506..056d535ce438b 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts @@ -60,7 +60,6 @@ describe('listTypes()', () => { unsecuredSavedObjectsClient: savedObjectsClientMock.create(), inMemoryConnectors: [], actionExecutor: actionExecutorMock.create(), - ephemeralExecutionEnqueuer: jest.fn(), bulkExecutionEnqueuer: jest.fn(), request: httpServerMock.createKibanaRequest(), authorization: actionsAuthorizationMock.create() as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index a92bff9719559..539ada46a094a 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -6,13 +6,8 @@ */ import { SavedObjectsBulkResponse, SavedObjectsClientContract, Logger } from '@kbn/core/server'; -import { RunNowResult, TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; -import { - RawAction, - ActionTypeRegistryContract, - InMemoryConnector, - ActionTaskExecutorParams, -} from './types'; +import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; +import { RawAction, ActionTypeRegistryContract, InMemoryConnector } 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'; @@ -215,43 +210,6 @@ export function createBulkExecutionEnqueuerFunction({ }; } -export function createEphemeralExecutionEnqueuerFunction({ - taskManager, - actionTypeRegistry, - inMemoryConnectors, - logger, -}: CreateExecuteFunctionOptions): ExecutionEnqueuer { - return async function execute( - unsecuredSavedObjectsClient: SavedObjectsClientContract, - { id, params, spaceId, source, consumer, apiKey, executionId }: ExecuteOptions - ): Promise { - const { connector } = await getConnector(unsecuredSavedObjectsClient, inMemoryConnectors, id); - - validateConnector({ id, connector, actionTypeRegistry }); - - const taskParams: ActionTaskExecutorParams = { - spaceId, - taskParams: { - actionId: id, - consumer, - // Saved Objects won't allow us to enforce unknown rather than any - // eslint-disable-next-line @typescript-eslint/no-explicit-any - params: params as Record, - ...(apiKey ? { apiKey } : {}), - ...(executionId ? { executionId } : {}), - }, - ...executionSourceAsSavedObjectReferences(source), - }; - - return taskManager.ephemeralRunNow({ - taskType: `actions:${connector.actionTypeId}`, - params: taskParams, - state: {}, - scope: ['actions'], - }); - }; -} - function validateConnector({ id, connector, @@ -287,21 +245,6 @@ function executionSourceAsSavedObjectReferences(executionSource: ActionExecutorO : {}; } -async function getConnector( - unsecuredSavedObjectsClient: SavedObjectsClientContract, - inMemoryConnectors: InMemoryConnector[], - actionId: string -): Promise<{ connector: InMemoryConnector | RawAction; isInMemory: boolean }> { - const inMemoryAction = inMemoryConnectors.find((action) => action.id === actionId); - - if (inMemoryAction) { - return { connector: inMemoryAction, isInMemory: true }; - } - - const { attributes } = await unsecuredSavedObjectsClient.get('action', actionId); - return { connector: attributes, isInMemory: false }; -} - async function getConnectors( unsecuredSavedObjectsClient: SavedObjectsClientContract, inMemoryConnectors: InMemoryConnector[], diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index b0f9db0ef700c..799fdb80f39af 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -82,7 +82,6 @@ export interface ExecuteOptions { actionId: string; consumer?: string; executionId?: string; - isEphemeral?: boolean; params: Record; relatedSavedObjects?: RelatedSavedObjects; request: KibanaRequest; @@ -133,7 +132,6 @@ export class ActionExecutor { actionId, consumer, executionId, - isEphemeral, request, params, relatedSavedObjects, @@ -175,7 +173,6 @@ export class ActionExecutor { }, executeLabel: `execute_action`, executionId, - isEphemeral, namespace, params, relatedSavedObjects, @@ -367,7 +364,6 @@ export class ActionExecutor { checkCanExecuteFn, executeLabel, executionId, - isEphemeral, namespace, params, relatedSavedObjects, @@ -512,7 +508,6 @@ export class ActionExecutor { params: validatedParams, config: validatedConfig, secrets: validatedSecrets, - isEphemeral, taskInfo, configurationUtilities, logger, diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index 9733b56638d77..0dc2b2f3f5c9a 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -35,7 +35,6 @@ import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; const executeParamsFields = [ 'actionId', - 'isEphemeral', 'params', 'relatedSavedObjects', 'executionId', @@ -173,7 +172,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -233,7 +231,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '9', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], @@ -289,7 +286,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -346,7 +342,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -407,7 +402,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -569,7 +563,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], @@ -627,7 +620,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [ @@ -680,7 +672,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [ @@ -739,7 +730,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, request: { headers: { @@ -785,7 +775,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index cf1f9eed87c32..b718a32a2e4ad 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -32,7 +32,6 @@ import { ActionTaskParams, ActionTypeExecutorResult, ActionTypeRegistryContract, - isPersistedActionTask, SpaceIdToNamespaceFunction, } from '../types'; import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from '../constants/saved_objects'; @@ -128,7 +127,6 @@ export class TaskRunnerFactory { executorResult = await actionExecutor.execute({ params, actionId: actionId as string, - isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), request, taskInfo, executionId, @@ -209,19 +207,17 @@ export class TaskRunnerFactory { }, cleanup: async () => { // Cleanup action_task_params object now that we're done with it - if (isPersistedActionTask(actionTaskExecutorParams)) { - try { - await savedObjectsRepository.delete( - ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - actionTaskExecutorParams.actionTaskParamsId, - { refresh: false, namespace: spaceIdToNamespace(actionTaskExecutorParams.spaceId) } - ); - } catch (e) { - // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) - logger.error( - `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` - ); - } + try { + await savedObjectsRepository.delete( + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + actionTaskExecutorParams.actionTaskParamsId, + { refresh: false, namespace: spaceIdToNamespace(actionTaskExecutorParams.spaceId) } + ); + } catch (e) { + // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) + logger.error( + `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` + ); } }, }; @@ -252,45 +248,41 @@ async function getActionTaskParams( ): Promise { const { spaceId } = executorParams; const namespace = spaceIdToNamespace(spaceId); - if (isPersistedActionTask(executorParams)) { - try { - const actionTask = - await encryptedSavedObjectsClient.getDecryptedAsInternalUser( - ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - executorParams.actionTaskParamsId, - { namespace } - ); - const { - attributes: { relatedSavedObjects }, - references, - } = actionTask; + try { + const actionTask = + await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + executorParams.actionTaskParamsId, + { namespace } + ); + const { + attributes: { relatedSavedObjects }, + references, + } = actionTask; - const { actionId, relatedSavedObjects: injectedRelatedSavedObjects } = - injectSavedObjectReferences(references, relatedSavedObjects as RelatedSavedObjects); + const { actionId, relatedSavedObjects: injectedRelatedSavedObjects } = + injectSavedObjectReferences(references, relatedSavedObjects as RelatedSavedObjects); - return { - ...actionTask, - attributes: { - ...actionTask.attributes, - ...(actionId ? { actionId } : {}), - ...(relatedSavedObjects ? { relatedSavedObjects: injectedRelatedSavedObjects } : {}), - }, - }; - } catch (e) { - const errorSource = SavedObjectsErrorHelpers.isNotFoundError(e) - ? TaskErrorSource.USER - : TaskErrorSource.FRAMEWORK; - logger.error( - `Failed to load action task params ${executorParams.actionTaskParamsId}: ${e.message}`, - { tags: ['connector-run-failed', `${errorSource}-error`] } - ); - if (SavedObjectsErrorHelpers.isNotFoundError(e)) { - throw createRetryableError(createTaskRunError(e, errorSource), true); - } + return { + ...actionTask, + attributes: { + ...actionTask.attributes, + ...(actionId ? { actionId } : {}), + ...(relatedSavedObjects ? { relatedSavedObjects: injectedRelatedSavedObjects } : {}), + }, + }; + } catch (e) { + const errorSource = SavedObjectsErrorHelpers.isNotFoundError(e) + ? TaskErrorSource.USER + : TaskErrorSource.FRAMEWORK; + logger.error( + `Failed to load action task params ${executorParams.actionTaskParamsId}: ${e.message}`, + { tags: ['connector-run-failed', `${errorSource}-error`] } + ); + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { throw createRetryableError(createTaskRunError(e, errorSource), true); } - } else { - return { attributes: executorParams.taskParams, references: executorParams.references ?? [] }; + throw createRetryableError(createTaskRunError(e, errorSource), true); } } diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index edfd7606950c1..012f602398e64 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -48,10 +48,7 @@ import { resolveCustomHosts } from './lib/custom_host_settings'; import { events } from './lib/event_based_telemetry'; import { ActionsClient } from './actions_client/actions_client'; import { ActionTypeRegistry } from './action_type_registry'; -import { - createEphemeralExecutionEnqueuerFunction, - createBulkExecutionEnqueuerFunction, -} from './create_execute_function'; +import { createBulkExecutionEnqueuerFunction } from './create_execute_function'; import { registerActionsUsageCollector } from './usage'; import { ActionExecutor, @@ -480,14 +477,6 @@ export class ActionsPlugin implements Plugin; @@ -238,27 +236,11 @@ export interface ActionTaskParams extends SavedObjectAttributes { source?: string; } -interface PersistedActionTaskExecutorParams { +export interface ActionTaskExecutorParams { spaceId: string; actionTaskParamsId: string; } -interface EphemeralActionTaskExecutorParams { - spaceId: string; - taskParams: ActionTaskParams; - references?: SavedObjectReference[]; -} - -export type ActionTaskExecutorParams = - | PersistedActionTaskExecutorParams - | EphemeralActionTaskExecutorParams; - -export function isPersistedActionTask( - actionTask: ActionTaskExecutorParams -): actionTask is PersistedActionTaskExecutorParams { - return typeof (actionTask as PersistedActionTaskExecutorParams).actionTaskParamsId === 'string'; -} - export interface ProxySettings { proxyUrl: string; proxyBypassHosts: Set | undefined; diff --git a/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts b/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts index 0e92d765a3d17..c4ad3c43ce071 100644 --- a/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts +++ b/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts @@ -23,7 +23,7 @@ export const installElser = async ({ inference_config: { service: 'elasticsearch', service_settings: { - num_allocations: 1, + adaptive_allocations: { enabled: true }, num_threads: 1, model_id: '.elser_model_2', }, diff --git a/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx b/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx new file mode 100644 index 0000000000000..d3d74d3913084 --- /dev/null +++ b/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { memoize } from 'lodash'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { PersistableStateAttachmentViewProps } from '@kbn/cases-plugin/public/client/attachment_framework/types'; +import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiDescriptionList } from '@elastic/eui'; +import type { + LogRateAnalysisEmbeddableWrapper, + LogRateAnalysisEmbeddableWrapperProps, +} from '../shared_components/log_rate_analysis_embeddable_wrapper'; + +export const initComponent = memoize( + (fieldFormats: FieldFormatsStart, LogRateAnalysisComponent: LogRateAnalysisEmbeddableWrapper) => { + return React.memo((props: PersistableStateAttachmentViewProps) => { + const { persistableStateAttachmentState } = props; + const dataFormatter = fieldFormats.deserialize({ + id: FIELD_FORMAT_IDS.DATE, + }); + const inputProps = + persistableStateAttachmentState as unknown as LogRateAnalysisEmbeddableWrapperProps; + + const listItems = [ + { + title: ( + + ), + description: `${dataFormatter.convert( + inputProps.timeRange.from + )} - ${dataFormatter.convert(inputProps.timeRange.to)}`, + }, + ]; + + return ( + <> + + + + ); + }); + } +); diff --git a/x-pack/plugins/aiops/public/cases/register_cases.tsx b/x-pack/plugins/aiops/public/cases/register_cases.tsx index b3b6efaf16d28..b98aca16fee7d 100644 --- a/x-pack/plugins/aiops/public/cases/register_cases.tsx +++ b/x-pack/plugins/aiops/public/cases/register_cases.tsx @@ -12,8 +12,10 @@ import type { CasesPublicSetup } from '@kbn/cases-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '@kbn/aiops-change-point-detection/constants'; import { CASES_ATTACHMENT_LOG_PATTERN } from '@kbn/aiops-log-pattern-analysis/constants'; +import { CASES_ATTACHMENT_LOG_RATE_ANALYSIS } from '@kbn/aiops-log-rate-analysis/constants'; import { getChangePointDetectionComponent, + getLogRateAnalysisEmbeddableWrapperComponent, getPatternAnalysisComponent, } from '../shared_components'; import type { AiopsPluginStartDeps } from '../types'; @@ -47,6 +49,14 @@ export function registerCases( }; }), }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), }); const LogPatternAttachmentComponent = getPatternAnalysisComponent(coreStart, pluginStart); @@ -71,5 +81,53 @@ export function registerCases( return { default: initComponent(pluginStart.fieldFormats, LogPatternAttachmentComponent) }; }), }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), + }); + + const LogRateAnalysisEmbeddableWrapperComponent = getLogRateAnalysisEmbeddableWrapperComponent( + coreStart, + pluginStart + ); + + cases.attachmentFramework.registerPersistableState({ + id: CASES_ATTACHMENT_LOG_RATE_ANALYSIS, + icon: 'machineLearningApp', + displayName: i18n.translate('xpack.aiops.logRateAnalysis.cases.attachmentName', { + defaultMessage: 'Log rate analysis', + }), + getAttachmentViewObject: () => ({ + event: ( + + ), + timelineAvatar: 'machineLearningApp', + children: React.lazy(async () => { + const { initComponent } = await import('./log_rate_analysis_attachment'); + + return { + default: initComponent( + pluginStart.fieldFormats, + LogRateAnalysisEmbeddableWrapperComponent + ), + }; + }), + }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), }); } diff --git a/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx b/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx index 9f4f6f1deb5bd..b56493cf03bdb 100644 --- a/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx +++ b/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx @@ -45,19 +45,25 @@ export const DocumentCountContent: FC = ({ const { documentStats } = useAppSelector((s) => s.logRateAnalysis); const { sampleProbability, totalCount, documentCountStats } = documentStats; + const isCasesEmbedding = embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.CASES; + + const isEmbeddedInDashboardOrCases = + embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD || isCasesEmbedding; + if (documentCountStats === undefined) { - return totalCount !== undefined && embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD ? ( + return totalCount !== undefined && !isEmbeddedInDashboardOrCases ? ( ) : null; } - if (embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD) { + if (isEmbeddedInDashboardOrCases) { return ( ); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx index 5bf415c5ccfc9..f4c25eafa5da4 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx @@ -401,9 +401,6 @@ export const LogCategorizationDiscover: FC = ( ); const style = css({ overflowY: 'auto', - '.kbnDocTableWrapper': { - overflowX: 'hidden', - }, }); const actions = getActions(false); diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx index 89a8c9aee19ae..0c0880ec3987e 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx @@ -25,6 +25,7 @@ import { AIOPS_STORAGE_KEYS } from '../../types/storage'; import { LogRateAnalysisPage } from './log_rate_analysis_page'; import { timeSeriesDataViewWarning } from '../../application/utils/time_series_dataview_check'; +import { FilterQueryContextProvider } from '../../hooks/use_filters_query'; const localStorage = new Storage(window.localStorage); @@ -58,6 +59,8 @@ export const LogRateAnalysisAppState: FC = ({ if (warning !== null) { return <>{warning}; } + const CasesContext = appContextValue.cases?.ui.getCasesContext() ?? React.Fragment; + const casesPermissions = appContextValue.cases?.helpers.canUseCases(); const datePickerDeps: DatePickerDependencies = { ...pick(appContextValue, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), @@ -67,17 +70,21 @@ export const LogRateAnalysisAppState: FC = ({ return ( - - - - - - - - - - - + + + + + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx index c8c9bad1568a4..d7e68ae42799c 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx @@ -26,15 +26,29 @@ import { EuiSpacer, EuiSwitch, } from '@elastic/eui'; +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis/window_parameters'; +import type { SignificantItem } from '@kbn/ml-agg-utils'; +import { useCasesModal } from '../../../hooks/use_cases_modal'; import { useDataSource } from '../../../hooks/use_data_source'; import type { LogRateAnalysisEmbeddableState } from '../../../embeddables/log_rate_analysis/types'; import { useAiopsAppContext } from '../../../hooks/use_aiops_app_context'; const SavedObjectSaveModalDashboard = withSuspense(LazySavedObjectSaveModalDashboard); -export const LogRateAnalysisAttachmentsMenu = () => { +interface LogRateAnalysisAttachmentsMenuProps { + windowParameters?: WindowParameters; + showLogRateAnalysisResults: boolean; + significantItems: SignificantItem[]; +} + +export const LogRateAnalysisAttachmentsMenu = ({ + windowParameters, + showLogRateAnalysisResults, + significantItems, +}: LogRateAnalysisAttachmentsMenuProps) => { const { application: { capabilities }, + cases, embeddable, } = useAiopsAppContext(); const { dataView } = useDataSource(); @@ -44,9 +58,19 @@ export const LogRateAnalysisAttachmentsMenu = () => { const [dashboardAttachmentReady, setDashboardAttachmentReady] = useState(false); const timeRange = useTimeRangeUpdates(); + const absoluteTimeRange = useTimeRangeUpdates(true); + + const openCasesModalCallback = useCasesModal(EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE); const canEditDashboards = capabilities.dashboard.createNew; + const { create: canCreateCase, update: canUpdateCase } = cases?.helpers?.canUseCases() ?? { + create: false, + update: false, + }; + + const isCasesAttachmentEnabled = showLogRateAnalysisResults && significantItems.length > 0; + const onSave: SaveModalDashboardProps['onSave'] = useCallback( ({ dashboardId, newTitle, newDescription }) => { const stateTransfer = embeddable!.getStateTransfer(); @@ -71,6 +95,19 @@ export const LogRateAnalysisAttachmentsMenu = () => { [dataView.id, embeddable, applyTimeRange, timeRange] ); + const caseAttachmentTooltipContent = useMemo(() => { + if (!showLogRateAnalysisResults) { + return i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseTooltipNoAnalysis', { + defaultMessage: 'Run the analysis first to add results to a case.', + }); + } + if (significantItems.length === 0) { + return i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseTooltipNoResults', { + defaultMessage: 'Cannot add to case because the analysis did not produce any results.', + }); + } + }, [showLogRateAnalysisResults, significantItems.length]); + const panels = useMemo>(() => { return [ { @@ -88,6 +125,31 @@ export const LogRateAnalysisAttachmentsMenu = () => { }, ] : []), + ...(canUpdateCase || canCreateCase + ? [ + { + name: i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseLabel', { + defaultMessage: 'Add to case', + }), + 'data-test-subj': 'aiopsLogRateAnalysisAttachToCaseButton', + disabled: !isCasesAttachmentEnabled, + ...(!isCasesAttachmentEnabled + ? { + toolTipProps: { position: 'left' as const }, + toolTipContent: caseAttachmentTooltipContent, + } + : {}), + onClick: () => { + setIsActionMenuOpen(false); + openCasesModalCallback({ + dataViewId: dataView.id, + timeRange: absoluteTimeRange, + ...(windowParameters && { windowParameters }), + }); + }, + }, + ] + : []), ], }, { @@ -131,7 +193,18 @@ export const LogRateAnalysisAttachmentsMenu = () => { ), }, ]; - }, [canEditDashboards, applyTimeRange]); + }, [ + canEditDashboards, + canUpdateCase, + canCreateCase, + isCasesAttachmentEnabled, + caseAttachmentTooltipContent, + applyTimeRange, + openCasesModalCallback, + dataView.id, + absoluteTimeRange, + windowParameters, + ]); return ( <> diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx index 29ac8d0efffc8..fb3c17634fd31 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx @@ -217,7 +217,13 @@ export const LogRateAnalysisContent: FC = ({ barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} barStyleAccessor={barStyleAccessor} - attachmentsMenu={} + attachmentsMenu={ + + } /> )} diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx index 1eb4f8fd0af0d..42fa509e6ce40 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx @@ -333,6 +333,8 @@ export const LogRateAnalysisResults: FC = ({ }, 0); const foundGroups = groupTableItems.length > 0 && groupItemCount > 0; + const isAnalysisControlsDisabled = embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.CASES; + return (
        = ({ onReset={onReset} shouldRerunAnalysis={shouldRerunAnalysis || searchQueryUpdated} analysisInfo={} + isAnalysisControlsDisabled={isAnalysisControlsDisabled} > <> {embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD && ( diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx index 765f1435a93ad..a9a030ecd16b8 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx @@ -16,6 +16,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { TableActionButton } from './table_action_button'; import { getTableItemAsKQL } from './get_table_item_as_kql'; +import { useFilterQueryUpdates } from '../../hooks/use_filters_query'; const viewInDiscoverMessage = i18n.translate( 'xpack.aiops.logRateAnalysis.resultsTable.linksMenu.viewInDiscover', @@ -32,6 +33,10 @@ export const useViewInDiscoverAction = (dataViewId?: string): TableItemAction => [share?.url.locators] ); + // We cannot rely on the time range from AiOps App context because it is not always in sync with the time range used for analysis. + // E.g. In the case of an embeddable inside cases, the time range is fixed and not coming from the time picker. + const { timeRange } = useFilterQueryUpdates(); + const discoverUrlError = useMemo(() => { if (!application.capabilities.discover?.show) { const discoverNotEnabled = i18n.translate( @@ -69,7 +74,7 @@ export const useViewInDiscoverAction = (dataViewId?: string): TableItemAction => if (discoverLocator !== undefined) { const url = await discoverLocator.getRedirectUrl({ indexPatternId: dataViewId, - timeRange: data.query.timefilter.timefilter.getTime(), + timeRange, filters: data.query.filterManager.getFilters(), query: { language: SEARCH_QUERY_LANGUAGE.KUERY, diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx index d92ce014d68fb..e96df8d140a14 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx @@ -18,6 +18,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { TableActionButton } from './table_action_button'; import { getTableItemAsKQL } from './get_table_item_as_kql'; +import { useFilterQueryUpdates } from '../../hooks/use_filters_query'; const isLogPattern = (tableItem: SignificantItem | GroupTableItem) => isSignificantItem(tableItem) && tableItem.type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN; @@ -34,6 +35,10 @@ export const useViewInLogPatternAnalysisAction = (dataViewId?: string): TableIte const mlLocator = useMemo(() => share?.url.locators.get('ML_APP_LOCATOR'), [share?.url.locators]); + // We cannot rely on the time range from AiOps App context because it is not always in sync with the time range used for analysis. + // E.g. In the case of an embeddable inside cases, the time range is fixed and not coming from the time picker. + const { timeRange } = useFilterQueryUpdates(); + const generateLogPatternAnalysisUrl = async ( groupTableItem: GroupTableItem | SignificantItem ) => { @@ -57,7 +62,9 @@ export const useViewInLogPatternAnalysisAction = (dataViewId?: string): TableIte page: 'aiops/log_categorization', pageState: { index: dataViewId, - timeRange: data.query.timefilter.timefilter.getTime(), + globalState: { + time: timeRange, + }, appState, }, }); diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx index 592ec32cef120..6d1ea7d2e03c1 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx @@ -37,6 +37,8 @@ import type { LogRateAnalysisEmbeddableState, } from './types'; +export type EmbeddableLogRateAnalysisType = typeof EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE; + export const getLogRateAnalysisEmbeddableFactory = ( getStartServices: StartServicesAccessor ) => { diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts index 9d8a49b8f0e9c..d155546e28bf6 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts @@ -11,7 +11,7 @@ import type { LogRateAnalysisComponentApi, LogRateAnalysisEmbeddableState } from type LogRateAnalysisEmbeddableCustomState = Omit< LogRateAnalysisEmbeddableState, - 'timeRange' | 'title' | 'description' | 'hidePanelTitles' + 'timeRange' | 'title' | 'description' | 'hidePanelTitles' | 'windowParameters' >; export const initializeLogRateAnalysisControls = (rawState: LogRateAnalysisEmbeddableState) => { diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts index d2255e6dacb87..28a68cecd36f3 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis'; import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; import type { HasEditCapabilities, @@ -28,6 +29,7 @@ export type LogRateAnalysisEmbeddableApi = DefaultEmbeddableApi; diff --git a/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts b/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts index 8ec73a21f9bbd..745506a0a1ae2 100644 --- a/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts +++ b/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts @@ -13,14 +13,21 @@ import type { EmbeddableChangePointChartType } from '../embeddables/change_point import { useAiopsAppContext } from './use_aiops_app_context'; import type { EmbeddablePatternAnalysisType } from '../embeddables/pattern_analysis/embeddable_pattern_analysis_factory'; import type { PatternAnalysisEmbeddableRuntimeState } from '../embeddables/pattern_analysis/types'; +import type { EmbeddableLogRateAnalysisType } from '../embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory'; +import type { LogRateAnalysisEmbeddableRuntimeState } from '../embeddables/log_rate_analysis/types'; -type SupportedEmbeddableTypes = EmbeddableChangePointChartType | EmbeddablePatternAnalysisType; +type SupportedEmbeddableTypes = + | EmbeddableChangePointChartType + | EmbeddablePatternAnalysisType + | EmbeddableLogRateAnalysisType; type EmbeddableRuntimeState = T extends EmbeddableChangePointChartType ? ChangePointEmbeddableRuntimeState : T extends EmbeddablePatternAnalysisType ? PatternAnalysisEmbeddableRuntimeState + : T extends EmbeddableLogRateAnalysisType + ? LogRateAnalysisEmbeddableRuntimeState : never; /** diff --git a/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx b/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx index 9f2a88e73461c..f08f4f0e68bd9 100644 --- a/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx +++ b/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx @@ -10,10 +10,7 @@ import React, { useEffect, useMemo, useState, type FC } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; import type { Observable } from 'rxjs'; import { BehaviorSubject, combineLatest, distinctUntilChanged, map } from 'rxjs'; -import { createBrowserHistory } from 'history'; -import { UrlStateProvider } from '@kbn/ml-url-state'; -import { Router } from '@kbn/shared-ux-router'; import { AIOPS_EMBEDDABLE_ORIGIN } from '@kbn/aiops-common/constants'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; import { UI_SETTINGS } from '@kbn/data-service'; @@ -22,6 +19,7 @@ import type { TimeRange } from '@kbn/es-query'; import { DatePickerContextProvider } from '@kbn/ml-date-picker'; import type { SignificantItem } from '@kbn/ml-agg-utils'; +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis'; import { AiopsAppContext, type AiopsAppContextValue } from '../hooks/use_aiops_app_context'; import { DataSourceContextProvider } from '../hooks/use_data_source'; import { ReloadContextProvider } from '../hooks/use_reload'; @@ -60,6 +58,7 @@ export interface LogRateAnalysisEmbeddableWrapperProps { onLoading: (isLoading: boolean) => void; onRenderComplete: () => void; onError: (error: Error) => void; + windowParameters?: WindowParameters; } const LogRateAnalysisEmbeddableWrapperWithDeps: FC = ({ @@ -71,6 +70,7 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC timeRange, embeddingOrigin, lastReloadRequestTime, + windowParameters, }) => { const deps = useMemo(() => { const { lens, data, usageCollection, fieldFormats, charts, share, storage, unifiedSearch } = @@ -120,8 +120,6 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC ); }, [manualReload$]); - const history = createBrowserHistory(); - // We use the following pattern to track changes of dataViewId, and if there's // a change, we unmount and remount the complete inner component. This makes // sure the component is reinitialized correctly when the options of the @@ -150,26 +148,22 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC }} > {showComponent && ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + )}
        ); diff --git a/x-pack/plugins/aiops/server/register_cases.ts b/x-pack/plugins/aiops/server/register_cases.ts index 5649c88ca6327..ac126a74a5a21 100644 --- a/x-pack/plugins/aiops/server/register_cases.ts +++ b/x-pack/plugins/aiops/server/register_cases.ts @@ -9,6 +9,7 @@ import type { Logger } from '@kbn/core/server'; import type { CasesServerSetup } from '@kbn/cases-plugin/server'; import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '@kbn/aiops-change-point-detection/constants'; import { CASES_ATTACHMENT_LOG_PATTERN } from '@kbn/aiops-log-pattern-analysis/constants'; +import { CASES_ATTACHMENT_LOG_RATE_ANALYSIS } from '@kbn/aiops-log-rate-analysis/constants'; export function registerCasesPersistableState(cases: CasesServerSetup | undefined, logger: Logger) { if (cases) { @@ -19,6 +20,9 @@ export function registerCasesPersistableState(cases: CasesServerSetup | undefine cases.attachmentFramework.registerPersistableState({ id: CASES_ATTACHMENT_LOG_PATTERN, }); + cases.attachmentFramework.registerPersistableState({ + id: CASES_ATTACHMENT_LOG_RATE_ANALYSIS, + }); } catch (error) { logger.warn(`AIOPs failed to register cases persistable state`); } diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 234420f01c52f..7b4b8493e1ab8 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -78,7 +78,6 @@ "@kbn/ui-theme", "@kbn/apm-utils", "@kbn/ml-field-stats-flyout", - "@kbn/shared-ux-router", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts index 95f07bf3f7bda..57a9499779add 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts @@ -24,7 +24,8 @@ export const aggregateRulesRequestBodySchema = schema.object({ ) ), filter: schema.maybe(schema.string()), - filter_consumers: schema.maybe(schema.arrayOf(schema.string())), + rule_type_ids: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), }); export const aggregateRulesResponseBodySchema = schema.object({ diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts index 62cc67360b162..26e5283cede13 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts @@ -9,5 +9,5 @@ import { schema } from '@kbn/config-schema'; export const bulkUntrackByQueryBodySchema = schema.object({ query: schema.arrayOf(schema.any()), - feature_ids: schema.arrayOf(schema.string()), + rule_type_ids: schema.arrayOf(schema.string()), }); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts index 7722521d2b707..b8ebef499e7e0 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts @@ -8,8 +8,13 @@ export { findRulesRequestQuerySchema } from './schemas/latest'; export type { FindRulesRequestQuery, FindRulesResponse } from './types/latest'; -export { findRulesRequestQuerySchema as findRulesRequestQuerySchemaV1 } from './schemas/v1'; +export { + findRulesRequestQuerySchema as findRulesRequestQuerySchemaV1, + findRulesInternalRequestBodySchema as findRulesInternalRequestBodySchemaV1, +} from './schemas/v1'; + export type { FindRulesRequestQuery as FindRulesRequestQueryV1, + FindRulesInternalRequestBody as FindRulesInternalRequestBodyV1, FindRulesResponse as FindRulesResponseV1, } from './types/latest'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts index 1dece949a9556..06ebfdbacc54d 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts @@ -103,3 +103,35 @@ export const findRulesRequestQuerySchema = schema.object({ ) ), }); + +export const findRulesInternalRequestBodySchema = schema.object({ + per_page: schema.number({ + defaultValue: 10, + min: 0, + }), + page: schema.number({ + defaultValue: 1, + min: 1, + }), + search: schema.maybe(schema.string()), + default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { + defaultValue: 'OR', + }), + search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])), + sort_field: schema.maybe(schema.string()), + sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + has_reference: schema.maybe( + // use nullable as maybe is currently broken + // in config-schema + schema.nullable( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ) + ), + fields: schema.maybe(schema.arrayOf(schema.string())), + filter: schema.maybe(schema.string()), + rule_type_ids: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), +}); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts index 271e791282f43..e09b4871eabc9 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts @@ -7,9 +7,10 @@ import type { TypeOf } from '@kbn/config-schema'; import { RuleParamsV1, RuleResponseV1 } from '../../../response'; -import { findRulesRequestQuerySchemaV1 } from '..'; +import { findRulesRequestQuerySchemaV1, findRulesInternalRequestBodySchemaV1 } from '..'; export type FindRulesRequestQuery = TypeOf; +export type FindRulesInternalRequestBody = TypeOf; export interface FindRulesResponse { body: { diff --git a/x-pack/plugins/alerting/kibana.jsonc b/x-pack/plugins/alerting/kibana.jsonc index 0b5f930dbb34a..b99c0a26c901e 100644 --- a/x-pack/plugins/alerting/kibana.jsonc +++ b/x-pack/plugins/alerting/kibana.jsonc @@ -35,12 +35,11 @@ "usageCollection", "security", "monitoringCollection", - "spaces", - "serverless" + "spaces" ], "extraPublicDirs": [ "common", "common/parse_duration" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx index 7f3c25eeaf55d..04bab61eb5c6f 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx @@ -31,7 +31,6 @@ import { } from '@elastic/eui'; import { TIMEZONE_OPTIONS as UI_TIMEZONE_OPTIONS } from '@kbn/core-ui-settings-common'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { Filter } from '@kbn/es-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import type { KibanaServerError } from '@kbn/kibana-utils-plugin/public'; @@ -73,7 +72,10 @@ const useDefaultTimezone = () => { } return { defaultTimezone: kibanaTz, isBrowser: false }; }; -const TIMEZONE_OPTIONS = UI_TIMEZONE_OPTIONS.map((n) => ({ label: n })) ?? [{ label: 'UTC' }]; + +const TIMEZONE_OPTIONS = UI_TIMEZONE_OPTIONS.map((timezoneOption) => ({ + label: timezoneOption, +})) ?? [{ label: 'UTC' }]; export const CreateMaintenanceWindowForm = React.memo((props) => { const { onCancel, onSuccess, initialValue, maintenanceWindowId } = props; @@ -203,6 +205,7 @@ export const CreateMaintenanceWindowForm = React.memo ruleType.category))]; }, [validRuleTypes]); - const featureIds = useMemo(() => { + const ruleTypeIds = useMemo(() => { if (!Array.isArray(validRuleTypes) || !Array.isArray(categoryIds) || !mounted) { return []; } - const featureIdsSet = new Set(); + const uniqueRuleTypeIds = new Set(); validRuleTypes.forEach((ruleType) => { if (categoryIds.includes(ruleType.category)) { - featureIdsSet.add(ruleType.producer as ValidFeatureId); + uniqueRuleTypeIds.add(ruleType.id); } }); - return [...featureIdsSet]; + return [...uniqueRuleTypeIds]; }, [validRuleTypes, categoryIds, mounted]); const onCategoryIdsChange = useCallback( @@ -476,7 +479,7 @@ export const CreateMaintenanceWindowForm = React.memo {() => ( { it('renders correctly', () => { appMockRenderer.render( { it('should hide the search bar if isEnabled is false', () => { appMockRenderer.render( { it('should render loading if isLoading is true', () => { appMockRenderer.render( { const { - featureIds, + ruleTypeIds, query, filters, errors = [], @@ -76,7 +75,7 @@ export const MaintenanceWindowScopedQuery = React.memo( { + const features = featuresPluginMock.createStart(); + const securityPluginStart = securityMock.createStart(); + const alertingAuthorizationClientFactoryParams: jest.Mocked = + { + ruleTypeRegistry: ruleTypeRegistryMock.create(), + getSpace: jest.fn(), + getSpaceId: jest.fn(), + features, + }; -const securityPluginSetup = securityMock.createSetup(); -const securityPluginStart = securityMock.createStart(); + beforeEach(() => { + jest.clearAllMocks(); + }); -const alertingAuthorizationClientFactoryParams: jest.Mocked = - { - ruleTypeRegistry: ruleTypeRegistryMock.create(), - getSpace: jest.fn(), - getSpaceId: jest.fn(), - features, - }; + it('creates an alerting authorization client with proper constructor arguments when security is enabled', async () => { + const factory = new AlertingAuthorizationClientFactory(); -beforeEach(() => { - jest.resetAllMocks(); -}); + factory.initialize({ + securityPluginStart, + ...alertingAuthorizationClientFactoryParams, + }); + + const request = mockRouter.createKibanaRequest(); + + await factory.create(request); -test('creates an alerting authorization client with proper constructor arguments when security is enabled', async () => { - const factory = new AlertingAuthorizationClientFactory(); - factory.initialize({ - securityPluginSetup, - securityPluginStart, - ...alertingAuthorizationClientFactoryParams, + const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); + expect(AlertingAuthorization.create).toHaveBeenCalledWith({ + request, + authorization: securityPluginStart.authz, + ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, + features: alertingAuthorizationClientFactoryParams.features, + getSpace: expect.any(Function), + getSpaceId: expect.any(Function), + }); }); - const request = mockRouter.createKibanaRequest(); - factory.create(request); + it('creates an alerting authorization client with proper constructor arguments', async () => { + const factory = new AlertingAuthorizationClientFactory(); + factory.initialize(alertingAuthorizationClientFactoryParams); + const request = mockRouter.createKibanaRequest(); - const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); - expect(AlertingAuthorization).toHaveBeenCalledWith({ - request, - authorization: securityPluginStart.authz, - ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, - features: alertingAuthorizationClientFactoryParams.features, - getSpace: expect.any(Function), - getSpaceId: expect.any(Function), + await factory.create(request); + + const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); + expect(AlertingAuthorization.create).toHaveBeenCalledWith({ + request, + ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, + features: alertingAuthorizationClientFactoryParams.features, + getSpace: expect.any(Function), + getSpaceId: expect.any(Function), + }); }); -}); -test('creates an alerting authorization client with proper constructor arguments', async () => { - const factory = new AlertingAuthorizationClientFactory(); - factory.initialize(alertingAuthorizationClientFactoryParams); - const request = mockRouter.createKibanaRequest(); + it('throws when trying to initialize again and it is already initialized', async () => { + const factory = new AlertingAuthorizationClientFactory(); + factory.initialize(alertingAuthorizationClientFactoryParams); + + expect(() => + factory.initialize(alertingAuthorizationClientFactoryParams) + ).toThrowErrorMatchingInlineSnapshot( + `"AlertingAuthorizationClientFactory already initialized"` + ); + }); - factory.create(request); + it('throws when trying to create an instance and the factory is not initialized', async () => { + const request = mockRouter.createKibanaRequest(); + const factory = new AlertingAuthorizationClientFactory(); - const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); - expect(AlertingAuthorization).toHaveBeenCalledWith({ - request, - ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, - features: alertingAuthorizationClientFactoryParams.features, - getSpace: expect.any(Function), - getSpaceId: expect.any(Function), + await expect(() => factory.create(request)).rejects.toThrowErrorMatchingInlineSnapshot( + `"AlertingAuthorizationClientFactory must be initialized before calling create"` + ); }); }); diff --git a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts index ca366a6cee0e4..8c5a772501f2b 100644 --- a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts +++ b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts @@ -6,7 +6,7 @@ */ import { KibanaRequest } from '@kbn/core/server'; -import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; +import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; import { AlertingAuthorization } from './authorization/alerting_authorization'; @@ -14,7 +14,6 @@ import { RuleTypeRegistry } from './types'; export interface AlertingAuthorizationClientFactoryOpts { ruleTypeRegistry: RuleTypeRegistry; - securityPluginSetup?: SecurityPluginSetup; securityPluginStart?: SecurityPluginStart; getSpace: (request: KibanaRequest) => Promise; getSpaceId: (request: KibanaRequest) => string; @@ -23,33 +22,39 @@ export interface AlertingAuthorizationClientFactoryOpts { export class AlertingAuthorizationClientFactory { private isInitialized = false; - private ruleTypeRegistry!: RuleTypeRegistry; - private securityPluginStart?: SecurityPluginStart; - private features!: FeaturesPluginStart; - private getSpace!: (request: KibanaRequest) => Promise; - private getSpaceId!: (request: KibanaRequest) => string; + // The reason this is protected is because we'll get type collisions otherwise because we're using a type guard assert + // to ensure the options member is instantiated before using it in various places + // See for more info: https://stackoverflow.com/questions/66206180/typescript-typeguard-attribut-with-method + protected options?: AlertingAuthorizationClientFactoryOpts; public initialize(options: AlertingAuthorizationClientFactoryOpts) { if (this.isInitialized) { throw new Error('AlertingAuthorizationClientFactory already initialized'); } this.isInitialized = true; - this.getSpace = options.getSpace; - this.ruleTypeRegistry = options.ruleTypeRegistry; - this.securityPluginStart = options.securityPluginStart; - this.features = options.features; - this.getSpaceId = options.getSpaceId; + this.options = options; } - public create(request: KibanaRequest): AlertingAuthorization { - const { securityPluginStart, features } = this; - return new AlertingAuthorization({ - authorization: securityPluginStart?.authz, + public async create(request: KibanaRequest): Promise { + this.validateInitialization(); + + return AlertingAuthorization.create({ + authorization: this.options.securityPluginStart?.authz, request, - getSpace: this.getSpace, - getSpaceId: this.getSpaceId, - ruleTypeRegistry: this.ruleTypeRegistry, - features: features!, + getSpace: this.options.getSpace, + getSpaceId: this.options.getSpaceId, + ruleTypeRegistry: this.options.ruleTypeRegistry, + features: this.options.features, }); } + + private validateInitialization(): asserts this is this & { + options: AlertingAuthorizationClientFactoryOpts; + } { + if (!this.isInitialized || this.options == null) { + throw new Error( + 'AlertingAuthorizationClientFactory must be initialized before calling create' + ); + } + } } diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 36bf830e47f74..903c8764d801f 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -347,6 +347,7 @@ describe('Alerts Client', () => { rule: alertRuleData, kibanaVersion: '8.9.0', spaceId: 'space1', + isServerless: false, dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), }; maintenanceWindowsService.getMaintenanceWindows.mockReturnValue({ @@ -543,10 +544,58 @@ describe('Alerts Client', () => { }); describe('persistAlerts()', () => { - test('should index new alerts', async () => { - const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>( - alertsClientParams - ); + test('should index new alerts with refresh: wait_for in stateful', async () => { + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>({ + ...alertsClientParams, + isServerless: false, + }); + + await alertsClient.initializeExecution(defaultExecutionOpts); + + // Report 2 new alerts + const alertExecutorService = alertsClient.factory(); + alertExecutorService.create('1').scheduleActions('default'); + alertExecutorService.create('2').scheduleActions('default'); + + await alertsClient.processAlerts(processAlertsOpts); + alertsClient.logAlerts(logAlertsOpts); + + await alertsClient.persistAlerts(); + + const { alertsToReturn } = alertsClient.getAlertsToSerialize(); + const uuid1 = alertsToReturn['1'].meta?.uuid; + const uuid2 = alertsToReturn['2'].meta?.uuid; + + expect(clusterClient.bulk).toHaveBeenCalledWith({ + index: '.alerts-test.alerts-default', + refresh: 'wait_for', + require_alias: !useDataStreamForAlerts, + body: [ + { + create: { _id: uuid1, ...(useDataStreamForAlerts ? {} : { require_alias: true }) }, + }, + // new alert doc + getNewIndexedAlertDoc({ [ALERT_UUID]: uuid1 }), + { + create: { _id: uuid2, ...(useDataStreamForAlerts ? {} : { require_alias: true }) }, + }, + // new alert doc + getNewIndexedAlertDoc({ [ALERT_UUID]: uuid2, [ALERT_INSTANCE_ID]: '2' }), + ], + }); + expect(maintenanceWindowsService.getMaintenanceWindows).toHaveBeenCalledWith({ + eventLogger: alertingEventLogger, + request: fakeRequest, + ruleTypeCategory: 'test', + spaceId: 'space1', + }); + }); + + test('should index new alerts with refresh: true in stateless', async () => { + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>({ + ...alertsClientParams, + isServerless: true, + }); await alertsClient.initializeExecution(defaultExecutionOpts); @@ -659,7 +708,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -732,7 +781,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -867,7 +916,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -940,7 +989,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1039,7 +1088,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1196,7 +1245,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1314,7 +1363,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1518,7 +1567,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1602,6 +1651,7 @@ describe('Alerts Client', () => { shouldWrite: false, }, }, + isServerless: false, request: fakeRequest, namespace: 'default', rule: alertRuleData, @@ -2451,7 +2501,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2725,7 +2775,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2826,7 +2876,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2923,7 +2973,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts index 1bfa1de9e96d6..0c2340ba7cd2d 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts @@ -73,6 +73,7 @@ export interface AlertsClientParams extends CreateAlertsClientParams { elasticsearchClientPromise: Promise; kibanaVersion: string; dataStreamAdapter: DataStreamAdapter; + isServerless: boolean; } interface AlertsAffectedByMaintenanceWindows { @@ -109,6 +110,7 @@ export class AlertsClient< private runTimestampString: string | undefined; private rule: AlertRule; private ruleType: UntypedNormalizedRuleType; + private readonly isServerless: boolean; private indexTemplateAndPattern: IIndexPatternString; @@ -143,6 +145,7 @@ export class AlertsClient< this._isUsingDataStreams = this.options.dataStreamAdapter.isUsingDataStreams(); this.ruleInfoMessage = `for ${this.ruleType.id}:${this.options.rule.id} '${this.options.rule.name}'`; this.logTags = { tags: [this.ruleType.id, this.options.rule.id, 'alerts-client'] }; + this.isServerless = options.isServerless; } public async initializeExecution(opts: InitializeExecutionOpts) { @@ -555,7 +558,9 @@ export class AlertsClient< try { const response = await esClient.bulk({ - refresh: true, + // On serverless we can force a refresh to we don't wait for the longer refresh interval + // When too many refresh calls are done in a short period of time, they are throttled by stateless Elasticsearch + refresh: this.isServerless ? true : 'wait_for', index: this.indexTemplateAndPattern.alias, require_alias: !this.isUsingDataStreams(), body: bulkBody, diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts index c97fb9f31f82a..78339ed5906b0 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts @@ -100,6 +100,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -159,6 +160,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -219,6 +221,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -288,6 +291,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts index 4b4f632d4cb20..5b32cf507c815 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts @@ -275,6 +275,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -308,6 +309,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$: test$, + isServerless: false, }); await retryUntil( @@ -350,6 +352,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -372,6 +375,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -453,6 +457,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -495,6 +500,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -1516,6 +1522,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: true, }); await retryUntil( @@ -1561,6 +1568,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: true, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1586,6 +1594,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -1629,6 +1638,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1693,6 +1703,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1736,6 +1747,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1824,6 +1836,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1870,6 +1883,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1911,6 +1925,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1960,6 +1975,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2013,6 +2029,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -2067,6 +2084,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2134,6 +2152,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2205,6 +2224,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2283,6 +2303,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2341,6 +2362,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2362,6 +2384,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2383,6 +2406,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2412,6 +2436,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2444,6 +2469,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2481,6 +2507,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2516,6 +2543,7 @@ describe('Alerts Service', () => { timeoutMs: 10, dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error logger called', async () => logger.error.mock.calls.length > 0); @@ -2533,6 +2561,7 @@ describe('Alerts Service', () => { timeoutMs: 10, dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('debug logger called', async () => logger.debug.mock.calls.length > 0); diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts index 4f0ead6c54206..6a6dbbdb58dfc 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts @@ -59,6 +59,7 @@ interface AlertsServiceParams { timeoutMs?: number; dataStreamAdapter: DataStreamAdapter; elasticsearchAndSOAvailability$: Observable; + isServerless: boolean; } export interface CreateAlertsClientParams extends LegacyAlertsClientParams { @@ -120,6 +121,7 @@ export type PublicFrameworkAlertsService = PublicAlertsService & { export class AlertsService implements IAlertsService { private initialized: boolean; + private isServerless: boolean; private isInitializing: boolean = false; private resourceInitializationHelper: ResourceInstallationHelper; private registeredContexts: Map = new Map(); @@ -129,6 +131,7 @@ export class AlertsService implements IAlertsService { constructor(private readonly options: AlertsServiceParams) { this.initialized = false; + this.isServerless = options.isServerless; this.dataStreamAdapter = options.dataStreamAdapter; // Kick off initialization of common assets and save the promise @@ -245,6 +248,7 @@ export class AlertsService implements IAlertsService { spaceId: opts.spaceId, kibanaVersion: this.options.kibanaVersion, dataStreamAdapter: this.dataStreamAdapter, + isServerless: this.isServerless, }); } diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts index 54376012aa767..003673f9fdb92 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts @@ -15,10 +15,8 @@ import { setAlertsToUntracked } from './set_alerts_to_untracked'; let clusterClient: ElasticsearchClientMock; let logger: ReturnType<(typeof loggingSystemMock)['createLogger']>; -const getAuthorizedRuleTypesMock = jest.fn(); - +const getAllAuthorizedRuleTypesFindOperationMock = jest.fn(); const getAlertIndicesAliasMock = jest.fn(); - const ensureAuthorizedMock = jest.fn(); describe('setAlertsToUntracked()', () => { @@ -362,11 +360,16 @@ describe('setAlertsToUntracked()', () => { }); test('should untrack by query', async () => { - getAuthorizedRuleTypesMock.mockResolvedValue([ - { - id: 'test-rule-type', - }, - ]); + getAllAuthorizedRuleTypesFindOperationMock.mockResolvedValue( + new Map([ + [ + 'test-rule-type', + { + id: 'test-rule-type', + }, + ], + ]) + ); getAlertIndicesAliasMock.mockResolvedValue(['test-alert-index']); clusterClient.search.mockResponseOnce({ @@ -441,9 +444,9 @@ describe('setAlertsToUntracked()', () => { }, }, ], - featureIds: ['o11y'], + ruleTypeIds: ['my-rule-type-id'], spaceId: 'default', - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, + getAllAuthorizedRuleTypesFindOperation: getAllAuthorizedRuleTypesFindOperationMock, getAlertIndicesAlias: getAlertIndicesAliasMock, ensureAuthorized: ensureAuthorizedMock, logger, @@ -527,11 +530,16 @@ describe('setAlertsToUntracked()', () => { }); test('should return an empty array if the search returns zero results', async () => { - getAuthorizedRuleTypesMock.mockResolvedValue([ - { - id: 'test-rule-type', - }, - ]); + getAllAuthorizedRuleTypesFindOperationMock.mockResolvedValue( + new Map([ + [ + 'test-rule-type', + { + id: 'test-rule-type', + }, + ], + ]) + ); getAlertIndicesAliasMock.mockResolvedValue(['test-alert-index']); clusterClient.search.mockResponseOnce({ @@ -575,9 +583,9 @@ describe('setAlertsToUntracked()', () => { }, }, ], - featureIds: ['o11y'], + ruleTypeIds: ['my-rule-type-id'], spaceId: 'default', - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, + getAllAuthorizedRuleTypesFindOperation: getAllAuthorizedRuleTypesFindOperationMock, getAlertIndicesAlias: getAlertIndicesAliasMock, ensureAuthorized: ensureAuthorizedMock, logger, diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts index ed0c2cb21e06b..89c8d671de6a0 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts @@ -21,8 +21,8 @@ import { AlertStatus, } from '@kbn/rule-data-utils'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { AlertingAuthorizationEntity } from '../../authorization/alerting_authorization'; import type { RulesClientContext } from '../../rules_client'; +import { AlertingAuthorizationEntity } from '../../authorization/types'; type EnsureAuthorized = (opts: { ruleTypeId: string; consumer: string }) => Promise; @@ -32,9 +32,9 @@ export interface SetAlertsToUntrackedParams { alertUuids?: string[]; query?: QueryDslQueryContainer[]; spaceId?: RulesClientContext['spaceId']; - featureIds?: string[]; + ruleTypeIds?: string[]; isUsingQuery?: boolean; - getAuthorizedRuleTypes?: RulesClientContext['authorization']['getAuthorizedRuleTypes']; + getAllAuthorizedRuleTypesFindOperation?: RulesClientContext['authorization']['getAllAuthorizedRuleTypesFindOperation']; getAlertIndicesAlias?: RulesClientContext['getAlertIndicesAlias']; ensureAuthorized?: EnsureAuthorized; } @@ -155,21 +155,26 @@ const ensureAuthorizedToUntrack = async (params: SetAlertsToUntrackedParamsWithD }; const getAuthorizedAlertsIndices = async ({ - featureIds, - getAuthorizedRuleTypes, + ruleTypeIds, + getAllAuthorizedRuleTypesFindOperation, getAlertIndicesAlias, spaceId, logger, }: SetAlertsToUntrackedParamsWithDep) => { try { - const authorizedRuleTypes = - (await getAuthorizedRuleTypes?.(AlertingAuthorizationEntity.Alert, new Set(featureIds))) || - []; - const indices = getAlertIndicesAlias?.( - authorizedRuleTypes.map((art: { id: string }) => art.id), - spaceId - ); - return indices; + const authorizedRuleTypes = await getAllAuthorizedRuleTypesFindOperation?.({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); + + if (authorizedRuleTypes) { + return getAlertIndicesAlias?.( + Array.from(authorizedRuleTypes.keys()).map((id) => id), + spaceId + ); + } + + return []; } catch (error) { const errMessage = `Failed to get authorized rule types to untrack alerts by query: ${error}`; logger.error(errMessage); diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts index dab9d5f38f036..ade1a1f35b59e 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts @@ -241,12 +241,15 @@ describe('findBackfill()', () => { test('should successfully find backfill with no filter', async () => { const result = await rulesClient.findBackfill({ page: 1, perPage: 10 }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -286,12 +289,15 @@ describe('findBackfill()', () => { test('should successfully find backfill with rule id', async () => { const result = await rulesClient.findBackfill({ page: 1, perPage: 10, ruleIds: 'abc' }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -336,12 +342,15 @@ describe('findBackfill()', () => { start: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -400,12 +409,15 @@ describe('findBackfill()', () => { end: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -465,12 +477,15 @@ describe('findBackfill()', () => { end: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -546,12 +561,15 @@ describe('findBackfill()', () => { ruleIds: 'abc', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -627,12 +645,15 @@ describe('findBackfill()', () => { sortOrder: 'asc', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts index 522128d0385f8..3482d854bda1f 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts @@ -40,16 +40,16 @@ export async function findBackfill( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', consumer: 'ad_hoc_run_params.attributes.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( adHocRunAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts index b8f1e5af9c869..a0a79421c7358 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts @@ -251,12 +251,15 @@ describe('scheduleBackfill()', () => { const mockData = [getMockData(), getMockData({ ruleId: '2', end: '2023-11-17T08:00:00.000Z' })]; const result = await rulesClient.scheduleBackfill(mockData); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'alert.attributes.consumer', - ruleTypeId: 'alert.attributes.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'alert.attributes.consumer', + ruleTypeId: 'alert.attributes.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts index 534262aa31c31..2dec1a78e3171 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts @@ -46,10 +46,10 @@ export async function scheduleBackfill( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts index 57fb2bf8f48a4..23ccbf97cb6ce 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts @@ -23,7 +23,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/lib'; import { RegistryRuleType } from '../../../../rule_type_registry'; -import { fromKueryExpression, nodeTypes } from '@kbn/es-query'; +import { fromKueryExpression, nodeTypes, toKqlExpression } from '@kbn/es-query'; import { RecoveredActionGroup } from '../../../../../common'; import { DefaultRuleAggregationResult } from '../../../../routes/rule/apis/aggregate/types'; import { defaultRuleAggregationFactory } from '.'; @@ -78,24 +78,28 @@ beforeEach(() => { setGlobalDate(); describe('aggregate()', () => { - const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); + beforeEach(() => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, @@ -161,26 +165,16 @@ describe('aggregate()', () => { }); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); @@ -394,6 +388,34 @@ describe('aggregate()', () => { ]); }); + test('combines the filters with the auth filter correctly', async () => { + const authFilter = fromKueryExpression( + 'alert.attributes.alertTypeId:myType and alert.attributes.consumer:myApp' + ); + + authorization.getFindAuthorizationFilter.mockResolvedValue({ + filter: authFilter, + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.aggregate({ + options: { + ruleTypeIds: ['my-rule-type-id'], + consumers: ['bar'], + filter: `alert.attributes.tags: ['bar']`, + }, + aggs: defaultRuleAggregationFactory(), + }); + + const finalFilter = unsecuredSavedObjectsClient.find.mock.calls[0][0].filter; + + expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledTimes(1); + expect(toKqlExpression(finalFilter)).toMatchInlineSnapshot( + `"((alert.attributes.tags: ['bar'] AND alert.attributes.alertTypeId: my-rule-type-id AND alert.attributes.consumer: bar) AND (alert.attributes.alertTypeId: myType AND alert.attributes.consumer: myApp))"` + ); + }); + test('logs audit event when not authorized to aggregate rules', async () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); authorization.getFindAuthorizationFilter.mockRejectedValue(new Error('Unauthorized')); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts index 9011b971e629a..307e27184ca7e 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts @@ -5,8 +5,13 @@ * 2.0. */ -import { KueryNode, nodeBuilder } from '@kbn/es-query'; -import { isEmpty } from 'lodash'; +import type { KueryNode } from '@kbn/es-query'; +import { + buildConsumersFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from '../../../../rules_client/common/filters'; import { findRulesSo } from '../../../../data/rule'; import { AlertingAuthorizationEntity } from '../../../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; @@ -22,15 +27,15 @@ export async function aggregateRules>( params: AggregateParams ): Promise { const { options = {}, aggs } = params; - const { filter, page = 1, perPage = 0, filterConsumers, ...restOptions } = options; + const { filter, page = 1, perPage = 0, ruleTypeIds, consumers, ...restOptions } = options; let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts, - isEmpty(filterConsumers) ? undefined : new Set(filterConsumers) - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); + validateRuleAggregationFields(aggs); aggregateOptionsSchema.validate(options); } catch (error) { @@ -45,15 +50,21 @@ export async function aggregateRules>( const { filter: authorizationFilter } = authorizationTuple; const filterKueryNode = buildKueryNodeFilter(filter); + const ruleTypeIdsFilter = buildRuleTypeIdsFilter(ruleTypeIds); + const consumersFilter = buildConsumersFilter(consumers); + const combinedFilters = combineFilters( + [filterKueryNode, ruleTypeIdsFilter, consumersFilter], + 'and' + ); const { aggregations } = await findRulesSo({ savedObjectsClient: context.unsecuredSavedObjectsClient, savedObjectsFindOptions: { ...restOptions, - filter: - authorizationFilter && filterKueryNode - ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) - : authorizationFilter, + filter: combineFilterWithAuthorizationFilter( + combinedFilters, + authorizationFilter as KueryNode + ), page, perPage, aggs, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts index 7250094160a04..d26f48e2462f5 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts @@ -16,7 +16,8 @@ export const aggregateOptionsSchema = schema.object({ id: schema.string(), }) ), - filterConsumers: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), // filter type is `string | KueryNode`, but `KueryNode` has no schema to import yet filter: schema.maybe( schema.oneOf([schema.string(), schema.recordOf(schema.string(), schema.any())]) diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts index 2156fb91e8778..e146928efcfff 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts @@ -9,17 +9,9 @@ import { TypeOf } from '@kbn/config-schema'; import { KueryNode } from '@kbn/es-query'; import { aggregateOptionsSchema } from '../schemas'; -type AggregateOptionsSchemaTypes = TypeOf; export type AggregateOptions = TypeOf & { - search?: AggregateOptionsSchemaTypes['search']; - defaultSearchOperator?: AggregateOptionsSchemaTypes['defaultSearchOperator']; - searchFields?: AggregateOptionsSchemaTypes['searchFields']; - hasReference?: AggregateOptionsSchemaTypes['hasReference']; // Adding filter as in schema it's defined as any instead of KueryNode filter?: string | KueryNode; - page?: AggregateOptionsSchemaTypes['page']; - perPage?: AggregateOptionsSchemaTypes['perPage']; - filterConsumers?: string[]; }; export interface AggregateParams { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index 8868065fa43a5..f7d83545ec193 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -132,10 +132,10 @@ export async function bulkEditRules( const qNodeFilter = ids ? convertRuleIdsToKueryNode(ids) : qNodeQueryFilter; let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts index 304037782f6d3..e93f82da28cbe 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts @@ -41,12 +41,11 @@ async function bulkUntrackAlertsWithOCC(context: RulesClientContext, params: Bul if (!context.alertsService) throw new Error('unable to access alertsService'); const result = await context.alertsService.setAlertsToUntracked({ ...params, - featureIds: params.featureIds || [], + ruleTypeIds: params.ruleTypeIds || [], spaceId: context.spaceId, getAlertIndicesAlias: context.getAlertIndicesAlias, - getAuthorizedRuleTypes: context.authorization.getAuthorizedRuleTypes.bind( - context.authorization - ), + getAllAuthorizedRuleTypesFindOperation: + context.authorization.getAllAuthorizedRuleTypesFindOperation.bind(context.authorization), ensureAuthorized: async ({ ruleTypeId, consumer, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts index f597d9f5b6fa4..8a4affbc83c3f 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts @@ -11,5 +11,5 @@ export const bulkUntrackBodySchema = schema.object({ indices: schema.maybe(schema.arrayOf(schema.string())), alertUuids: schema.maybe(schema.arrayOf(schema.string())), query: schema.maybe(schema.arrayOf(schema.any())), - featureIds: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index 34e13b65d76c5..3514f8ce2237b 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -84,6 +84,12 @@ export async function createRule( throw Boom.badRequest(`Error validating create data - ${error.message}`); } + /** + * ruleTypeRegistry.get will throw a 400 (Bad request) + * error if the rule type is not registered. + */ + context.ruleTypeRegistry.get(data.alertTypeId); + let validationPayload: ValidateScheduleLimitResult = null; if (data.enabled) { validationPayload = await validateScheduleLimit({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts index e6bfd3408a538..369549d839c79 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts @@ -15,7 +15,7 @@ import { import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock'; -import { nodeTypes, fromKueryExpression } from '@kbn/es-query'; +import { nodeTypes, fromKueryExpression, toKqlExpression } from '@kbn/es-query'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; import { AlertingAuthorization } from '../../../../authorization/alerting_authorization'; @@ -92,23 +92,26 @@ jest.mock('../../../../rules_client/common/map_sort_field', () => ({ })); describe('find()', () => { - const listedTypes = new Set([ - { - actionGroups: [], - recoveryActionGroup: RecoveredActionGroup, - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); beforeEach(() => { @@ -163,26 +166,16 @@ describe('find()', () => { }); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup: RecoveredActionGroup, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); @@ -235,7 +228,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -349,7 +342,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -461,7 +454,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -513,13 +506,34 @@ describe('find()', () => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, }); + const injectReferencesFn = jest.fn().mockReturnValue({ bar: true, parameterThatIsSavedObjectId: '9', }); - ruleTypeRegistry.list.mockReturnValue( - new Set([ - ...listedTypes, + + const ruleTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + '123', { actionGroups: [], recoveryActionGroup: RecoveredActionGroup, @@ -536,8 +550,10 @@ describe('find()', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]) - ); + ], + ]); + + ruleTypeRegistry.list.mockReturnValue(ruleTypes); ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: 'myType', name: 'myType', @@ -750,12 +766,33 @@ describe('find()', () => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, }); + const injectReferencesFn = jest.fn().mockImplementation(() => { throw new Error('something went wrong!'); }); - ruleTypeRegistry.list.mockReturnValue( - new Set([ - ...listedTypes, + + const ruleTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + '123', { actionGroups: [], recoveryActionGroup: RecoveredActionGroup, @@ -772,8 +809,10 @@ describe('find()', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]) - ); + ], + ]); + + ruleTypeRegistry.list.mockReturnValue(ruleTypes); ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: 'myType', name: 'myType', @@ -792,6 +831,7 @@ describe('find()', () => { }, validLegacyConsumers: [], })); + ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: '123', name: 'Test', @@ -987,12 +1027,58 @@ describe('find()', () => { expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ fields: ['tags', 'alertTypeId', 'consumer'], - filter: null, + filter: undefined, sortField: undefined, type: RULE_SAVED_OBJECT_TYPE, }); expect(ensureRuleTypeIsAuthorized).toHaveBeenCalledWith('myType', 'myApp', 'rule'); }); + + test('calls getFindAuthorizationFilter correctly', async () => { + authorization.getFindAuthorizationFilter.mockResolvedValue({ + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.find({ options: { ruleTypeIds: ['foo'], consumers: ['bar'] } }); + + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'alert.attributes.consumer', + ruleTypeId: 'alert.attributes.alertTypeId', + }, + type: 'kql', + }, + }); + }); + + test('combines the filters with the auth filter correctly', async () => { + const filter = fromKueryExpression( + 'alert.attributes.alertTypeId:myType and alert.attributes.consumer:myApp' + ); + + authorization.getFindAuthorizationFilter.mockResolvedValue({ + filter, + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.find({ + options: { + ruleTypeIds: ['foo'], + consumers: ['bar'], + filter: `alert.attributes.tags: ['bar']`, + }, + }); + + const finalFilter = unsecuredSavedObjectsClient.find.mock.calls[0][0].filter; + + expect(toKqlExpression(finalFilter)).toMatchInlineSnapshot( + `"((alert.attributes.tags: ['bar'] AND alert.attributes.alertTypeId: foo AND alert.attributes.consumer: bar) AND (alert.attributes.alertTypeId: myType AND alert.attributes.consumer: myApp))"` + ); + }); }); describe('auditLogger', () => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts index 7e4efb2665f6b..26441a4474473 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts @@ -6,11 +6,17 @@ */ import Boom from '@hapi/boom'; -import { isEmpty, pick } from 'lodash'; -import { KueryNode, nodeBuilder } from '@kbn/es-query'; +import { pick } from 'lodash'; +import { KueryNode } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { + buildConsumersFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from '../../../../rules_client/common/filters'; +import { AlertingAuthorizationEntity } from '../../../../authorization/types'; import { SanitizedRule, Rule as DeprecatedRule, RawRule } from '../../../../types'; -import { AlertingAuthorizationEntity } from '../../../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { mapSortField, @@ -46,7 +52,7 @@ export async function findRules( ): Promise> { const { options, excludeFromPublicApi = false, includeSnoozeData = false } = params || {}; - const { fields, filterConsumers, ...restOptions } = options || {}; + const { fields, ruleTypeIds, consumers, ...restOptions } = options || {}; try { if (params) { @@ -58,11 +64,10 @@ export async function findRules( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts, - isEmpty(filterConsumers) ? undefined : new Set(filterConsumers) - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ @@ -76,6 +81,7 @@ export async function findRules( const { filter: authorizationFilter, ensureRuleTypeIsAuthorized } = authorizationTuple; const filterKueryNode = buildKueryNodeFilter(restOptions.filter as string | KueryNode); let sortField = mapSortField(restOptions.sortField); + if (excludeFromPublicApi) { try { validateOperationOnAttributes( @@ -111,6 +117,18 @@ export async function findRules( modifyFilterKueryNode({ astFilter: filterKueryNode }); } + const ruleTypeIdsFilter = buildRuleTypeIdsFilter(ruleTypeIds); + const consumersFilter = buildConsumersFilter(consumers); + const combinedFilters = combineFilters( + [filterKueryNode, ruleTypeIdsFilter, consumersFilter], + 'and' + ); + + const finalFilter = combineFilterWithAuthorizationFilter( + combinedFilters, + authorizationFilter as KueryNode + ); + const { page, per_page: perPage, @@ -121,10 +139,7 @@ export async function findRules( savedObjectsFindOptions: { ...modifiedOptions, sortField, - filter: - (authorizationFilter && filterKueryNode - ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) - : authorizationFilter) ?? filterKueryNode, + filter: finalFilter, fields: fields ? includeFieldsRequiredForAuthentication(fields) : fields, }, }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts index b766ffc283bb2..aec95d7f2c061 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts @@ -28,7 +28,8 @@ export const findRulesOptionsSchema = schema.object( filter: schema.maybe( schema.oneOf([schema.string(), schema.recordOf(schema.string(), schema.any())]) ), - filterConsumers: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), }, { unknowns: 'allow' } ); @@ -37,5 +38,4 @@ export const findRulesParamsSchema = schema.object({ options: schema.maybe(findRulesOptionsSchema), excludeFromPublicApi: schema.maybe(schema.boolean()), includeSnoozeData: schema.maybe(schema.boolean()), - featureIds: schema.maybe(schema.arrayOf(schema.string())), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts index 615a5b5db8672..77694f150c5a9 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts @@ -9,5 +9,4 @@ import { TypeOf } from '@kbn/config-schema'; import { findRulesOptionsSchema, findRulesParamsSchema } from '../schemas'; export type FindRulesOptions = TypeOf; - export type FindRulesParams = TypeOf; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.ts new file mode 100644 index 0000000000000..fd0a641df022c --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.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 { rulesClientContextMock } from '../../../../rules_client/rules_client.mock'; +import { RulesClient } from '../../../../rules_client'; + +describe('listRuleTypes', () => { + const rulesClientContext = rulesClientContextMock.create(); + let rulesClient: RulesClient; + + beforeEach(async () => { + jest.clearAllMocks(); + rulesClient = new RulesClient(rulesClientContext); + + rulesClientContext.ruleTypeRegistry.list = jest.fn().mockReturnValue( + new Map([ + ['apm.anomaly', { name: 'Anomaly' }], + ['.es-query', { name: 'ES rule type' }], + ]) + ); + rulesClientContext.ruleTypeRegistry.has = jest + .fn() + .mockImplementation((ruleTypeId: string) => ruleTypeId === '.es-query'); + + rulesClientContext.authorization.getAuthorizedRuleTypes = jest.fn().mockResolvedValue( + new Map([ + ['.es-query', { authorizedConsumers: { all: true, read: true } }], + ['.not-exist', { authorizedConsumers: { all: true, read: true } }], + ]) + ); + }); + + it('authorizes correctly', async () => { + await rulesClient.listRuleTypes(); + + expect(rulesClientContext.authorization.getAuthorizedRuleTypes).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + operations: ['get', 'create'], + ruleTypeIds: ['apm.anomaly', '.es-query'], + }); + }); + + it('returns the authorized rule types correctly and does not return non authorized or non existing rule types', async () => { + const res = await rulesClient.listRuleTypes(); + + expect(res).toEqual([{ name: 'ES rule type', authorizedConsumers: { all: true, read: true } }]); + }); +}); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts index 66256b4b7d7eb..4bcb6fdece3e2 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts @@ -6,16 +6,28 @@ */ import { - WriteOperations, - ReadOperations, AlertingAuthorizationEntity, + ReadOperations, + RegistryAlertTypeWithAuth, + WriteOperations, } from '../../../../authorization'; import { RulesClientContext } from '../../../../rules_client/types'; -export async function listRuleTypes(context: RulesClientContext) { - return await context.authorization.filterByRuleTypeAuthorization( - context.ruleTypeRegistry.list(), - [ReadOperations.Get, WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ); +export async function listRuleTypes( + context: RulesClientContext +): Promise { + const registeredRuleTypes = context.ruleTypeRegistry.list(); + + const authorizedRuleTypes = await context.authorization.getAuthorizedRuleTypes({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + operations: [ReadOperations.Get, WriteOperations.Create], + ruleTypeIds: Array.from(registeredRuleTypes.keys()).map((id) => id), + }); + + return Array.from(authorizedRuleTypes.entries()) + .filter(([id, _]) => context.ruleTypeRegistry.has(id)) + .map(([id, { authorizedConsumers }]) => ({ + ...registeredRuleTypes.get(id)!, + authorizedConsumers, + })); } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts index de356c3a2e2b9..2a84becfd83d6 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts @@ -66,23 +66,26 @@ const rulesClientParams: jest.Mocked = { isSystemAction: jest.fn(), }; -const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, +const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); beforeEach(() => { @@ -118,26 +121,16 @@ describe('getTags()', () => { unsecuredSavedObjectsClient.find.mockResolvedValue(getMockAggregationResult(['a', 'b', 'c'])); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts index c26fae42ce324..84a05ac67057a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts @@ -33,10 +33,10 @@ export async function getRuleTags( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts index e51a5c9b12c79..12e360c7cd644 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts @@ -14,12 +14,20 @@ export type AlertingAuthorizationMock = jest.Mocked; const createAlertingAuthorizationMock = () => { const mocked: AlertingAuthorizationMock = { ensureAuthorized: jest.fn(), - filterByRuleTypeAuthorization: jest.fn(), - getAuthorizationFilter: jest.fn(), - getAuthorizedRuleTypes: jest.fn(), - getFindAuthorizationFilter: jest.fn(), - getAugmentedRuleTypesWithAuthorization: jest.fn(), + getAuthorizedRuleTypes: jest.fn().mockResolvedValue(new Map()), + getFindAuthorizationFilter: jest.fn().mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: () => {}, + }), getSpaceId: jest.fn(), + getAllAuthorizedRuleTypes: jest + .fn() + .mockResolvedValue({ hasAllRequested: true, authorizedRuleTypes: new Map() }), + getAllAuthorizedRuleTypesFindOperation: jest.fn().mockResolvedValue(new Map()), + getAuthorizationFilter: jest.fn().mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: () => {}, + }), }; return mocked; }; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts index f1cfb99a6daaa..9c470823362d8 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts @@ -5,75 +5,53 @@ * 2.0. */ -import { KueryNode, fromKueryExpression, toKqlExpression } from '@kbn/es-query'; +import Boom from '@hapi/boom'; +import { KueryNode, toKqlExpression } from '@kbn/es-query'; import { KibanaRequest } from '@kbn/core/server'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { securityMock } from '@kbn/security-plugin/server/mocks'; -import { - FeaturesPluginStart as FeaturesStartContract, - KibanaFeature, -} from '@kbn/features-plugin/server'; +import { KibanaFeature } from '@kbn/features-plugin/server'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; -import { - AlertingAuthorization, - WriteOperations, - ReadOperations, - AlertingAuthorizationEntity, -} from './alerting_authorization'; -import { v4 as uuidv4 } from 'uuid'; -import { RecoveredActionGroup } from '../../common'; -import { NormalizedRuleType, RegistryRuleType } from '../rule_type_registry'; +import { AlertingAuthorization } from './alerting_authorization'; import { AlertingAuthorizationFilterType } from './alerting_authorization_kuery'; -import { schema } from '@kbn/config-schema'; - -const ruleTypeRegistry = ruleTypeRegistryMock.create(); -const features: jest.Mocked = featuresPluginMock.createStart(); -const request = {} as KibanaRequest; - -const getSpace = jest.fn(); -const getSpaceId = () => 'space1'; +import { httpServerMock } from '@kbn/core-http-server-mocks'; +import { CheckPrivilegesResponse } from '@kbn/security-plugin-types-server'; +import type { FeaturesPluginStart } from '@kbn/features-plugin/server'; +import { WriteOperations, AlertingAuthorizationEntity, ReadOperations } from './types'; +import { AlertingKibanaPrivilege } from '@kbn/features-plugin/common/alerting_kibana_privilege'; const mockAuthorizationAction = ( - type: string, - app: string, - alertingType: string, + ruleType: string, + consumer: string, + entity: string, operation: string -) => `${type}/${app}/${alertingType}/${operation}`; -function mockSecurity() { - const security = securityMock.createSetup(); - const authorization = security.authz; - // typescript is having trouble inferring jest's automocking - ( - authorization.actions.alerting.get as jest.MockedFunction< - typeof authorization.actions.alerting.get - > - ).mockImplementation(mockAuthorizationAction); - authorization.mode.useRbacForRequest.mockReturnValue(true); - return { authorization }; -} +) => `${ruleType}/${consumer}/${entity}/${operation}`; -function mockFeature(appName: string, typeName?: string | string[]) { - const typeNameArray = typeName ? (Array.isArray(typeName) ? typeName : [typeName]) : undefined; +function mockFeatureWithConsumers( + appName: string, + alertingFeatures?: AlertingKibanaPrivilege, + subFeature?: boolean +) { return new KibanaFeature({ id: appName, name: appName, app: [], category: { id: 'foo', label: 'foo' }, - ...(typeNameArray + ...(alertingFeatures ? { - alerting: typeNameArray, + alerting: alertingFeatures, } : {}), privileges: { all: { - ...(typeNameArray + ...(alertingFeatures ? { alerting: { rule: { - all: typeNameArray, + all: alertingFeatures, }, alert: { - all: typeNameArray, + all: alertingFeatures, }, }, } @@ -85,14 +63,14 @@ function mockFeature(appName: string, typeName?: string | string[]) { ui: [], }, read: { - ...(typeNameArray + ...(alertingFeatures ? { alerting: { rule: { - read: typeNameArray, + read: alertingFeatures, }, alert: { - read: typeNameArray, + read: alertingFeatures, }, }, } @@ -104,2480 +82,2219 @@ function mockFeature(appName: string, typeName?: string | string[]) { ui: [], }, }, - }); -} - -function mockFeatureWithSubFeature(appName: string, typeName: string) { - return new KibanaFeature({ - id: appName, - name: appName, - app: [], - category: { id: 'foo', label: 'foo' }, - ...(typeName + ...(subFeature ? { - alerting: [typeName], + subFeatures: [ + { + name: appName, + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'doSomethingAlertRelated', + name: 'sub feature alert', + includeIn: 'all', + alerting: { + rule: { + all: alertingFeatures, + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: ['doSomethingAlertRelated'], + }, + { + id: 'doSomethingAlertRelated', + name: 'sub feature alert', + includeIn: 'read', + alerting: { + rule: { + read: alertingFeatures, + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: ['doSomethingAlertRelated'], + }, + ], + }, + ], + }, + ], } : {}), - privileges: { - all: { - savedObject: { - all: [], - read: [], - }, - ui: [], - }, - read: { - savedObject: { - all: [], - read: [], - }, - ui: [], - }, - }, - subFeatures: [ - { - name: appName, - privilegeGroups: [ - { - groupType: 'independent', - privileges: [ - { - id: 'doSomethingAlertRelated', - name: 'sub feature alert', - includeIn: 'all', - alerting: { - rule: { - all: [typeName], - }, - }, - savedObject: { - all: [], - read: [], - }, - ui: ['doSomethingAlertRelated'], - }, - { - id: 'doSomethingAlertRelated', - name: 'sub feature alert', - includeIn: 'read', - alerting: { - rule: { - read: [typeName], - }, - }, - savedObject: { - all: [], - read: [], - }, - ui: ['doSomethingAlertRelated'], - }, - ], - }, - ], - }, - ], }); } -const myAppFeature = mockFeature('myApp', 'myType'); -const myOtherAppFeature = mockFeature('myOtherApp', 'myType'); -const myAppWithSubFeature = mockFeatureWithSubFeature('myAppWithSubFeature', 'myType'); -const myFeatureWithoutAlerting = mockFeature('myOtherApp'); - -beforeEach(() => { - jest.resetAllMocks(); - ruleTypeRegistry.get.mockImplementation((id) => ({ - id, - name: 'My Alert Type', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - async executor() { - return { state: {} }; - }, - category: 'test', - producer: 'myApp', - validate: { - params: schema.any(), - }, - validLegacyConsumers: [], - })); - features.getKibanaFeatures.mockReturnValue([ - myAppFeature, - myOtherAppFeature, - myAppWithSubFeature, - myFeatureWithoutAlerting, - ]); - getSpace.mockResolvedValue(undefined); -}); +type CheckPrivilegesResponseWithoutES = Omit & { + privileges: Omit; +}; describe('AlertingAuthorization', () => { - describe('constructor', () => { - test(`fetches the user's current space`, async () => { - const space = { - id: uuidv4(), - name: uuidv4(), - disabledFeatures: [], - }; - getSpace.mockResolvedValue(space); + const getSpace = jest.fn(); + const getSpaceId = () => 'space1'; + const allRegisteredConsumers = new Set(); + const ruleTypesConsumersMap = new Map>(); + + const checkPrivileges = jest.fn, []>(async () => ({ + username: 'elastic', + hasAllRequested: true, + privileges: { kibana: [] }, + })); + + const ruleTypeIds = ['rule-type-id-1', 'rule-type-id-2', 'rule-type-id-3', 'rule-type-id-4']; + + let request: KibanaRequest; + let ruleTypeRegistry = ruleTypeRegistryMock.create(); + let securityStart: ReturnType; + let features: jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + allRegisteredConsumers.clear(); + allRegisteredConsumers.clear(); + ruleTypesConsumersMap.clear(); + + securityStart = securityMock.createStart(); + securityStart.authz.mode.useRbacForRequest.mockReturnValue(true); + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + request = httpServerMock.createKibanaRequest(); + getSpace.mockResolvedValue(undefined); + + features = featuresPluginMock.createStart(); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('feature-id-1', [ + { + ruleTypeId: 'rule-type-id-1', + consumers: ['alerts', 'consumer-a'], + }, + { ruleTypeId: 'rule-type-id-2', consumers: ['alerts', 'consumer-b'] }, + ]), + mockFeatureWithConsumers('feature-id-2', [ + { + ruleTypeId: 'rule-type-id-1', + consumers: ['alerts', 'consumer-b'], + }, + { + ruleTypeId: 'rule-type-id-3', + consumers: ['alerts', 'consumer-c'], + }, + ]), + mockFeatureWithConsumers('feature-id-3', [ + { + ruleTypeId: 'rule-type-id-4', + consumers: ['consumer-d'], + }, + ]), + ]); + + const alertingGet = securityStart.authz.actions.alerting.get as jest.Mock; + alertingGet.mockImplementation(mockAuthorizationAction); + + ruleTypeRegistry = ruleTypeRegistryMock.create(); + ruleTypeRegistry.getAllTypes.mockReturnValue(ruleTypeIds); + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => + ruleTypeIds.includes(ruleTypeId) + ); + + // @ts-expect-error: only the id is needed for the tests + ruleTypeRegistry.get.mockImplementation((ruleTypeId: string) => ({ id: ruleTypeId })); + }); + + describe('create', () => { + beforeEach(() => { + jest.clearAllMocks(); + securityStart = securityMock.createStart(); + features = featuresPluginMock.createStart(); + + getSpace.mockReturnValue({ id: 'default', name: 'Default', disabledFeatures: [] }); + features.getKibanaFeatures.mockReturnValue([mockFeatureWithConsumers('my-feature-1')]); + }); + + it('creates an AlertingAuthorization object', async () => { + expect.assertions(2); - new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - expect(getSpace).toHaveBeenCalledWith(request); + await expect(authPromise).resolves.toBeDefined(); + await expect(authPromise).resolves.not.toThrow(); }); - }); - describe('ensureAuthorized', () => { - test('is a no-op when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ + it('creates an AlertingAuthorization object without spaces', async () => { + getSpace.mockReturnValue(undefined); + expect.assertions(2); + + const authPromise = AlertingAuthorization.create({ request, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + await expect(authPromise).resolves.toBeDefined(); + await expect(authPromise).resolves.not.toThrow(); + }); + + it('filters out disabled spaces and features without alerting', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: ['my-feature-1'], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-c', 'consumer-d'] }, + ]), + mockFeatureWithConsumers('my-feature-3'), + mockFeatureWithConsumers('my-feature-4', []), + ]); - test('is a no-op when the security license is disabled', async () => { - const { authorization } = mockSecurity(); - authorization.mode.useRbacForRequest.mockReturnValue(false); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, ruleTypeRegistry, - authorization, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(` + Set { + "consumer-c", + "consumer-d", + } + `); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(` + Map { + "rule-type-2" => Set { + "consumer-c", + "consumer-d", + }, + } + `); + }); + + it('removes duplicated consumers', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: [], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-a'] }, + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + ]); - test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when producer and consumer are the same', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(` + Set { + "consumer-a", + "consumer-b", + "consumer-c", + } + `); + }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + it('removes duplicated ruleTypes and consumers', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: [], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-a'] }, + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-e'] }, + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-d'] }, + ]), + ]); - test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when producer and consumer are the same', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, - }); + // @ts-expect-error: ruleTypesConsumersMap is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(` + Map { + "rule-type-1" => Set { + "consumer-a", + "consumer-b", + "consumer-d", + }, + "rule-type-2" => Set { + "consumer-a", + "consumer-b", + "consumer-c", + "consumer-e", + }, + } + `); + }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error when a generic error occurs', async () => { + expect.assertions(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], - }); - }); + getSpace.mockRejectedValue(new Error('Error')); - test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when consumer is alerts', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + await expect(authPromise).rejects.toThrow(); + }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }); + it.each([403, 404])( + `construct the AlertingAuthorization with empty features if the error is boom and %s`, + async (errorStatusCode: number) => { + getSpace.mockRejectedValue( + new Boom.Boom('Server error', { + statusCode: errorStatusCode, + message: 'my error message', + }) + ); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(`Map {}`); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(`Set {}`); + } + ); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error if the error is boom but not 403', async () => { + expect.assertions(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' + getSpace.mockRejectedValue( + new Boom.Boom('Server error', { statusCode: 400, message: 'my error message' }) ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); - test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when consumer is alerts', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'alerts', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + authorization: securityStart.authz, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], - }); + await expect(authPromise).rejects.toThrow(); }); + }); - test('ensures the user has privileges to execute rules for the specified rule type, operation and producer when producer is different from consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + describe('ensureAuthorized', () => { + beforeEach(() => { + jest.clearAllMocks(); + allRegisteredConsumers.clear(); + allRegisteredConsumers.add('myApp'); + }); + it('is a no-op when there is no authorization api', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myOtherApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create')], - }); + expect(checkPrivileges).not.toHaveBeenCalled(); }); - test('ensures the user has privileges to execute alerts for the specified rule type, operation and producer when producer is different from consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + it('is a no-op when the security license is disabled', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + consumer: 'myApp', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myOtherApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update')], - }); + expect(checkPrivileges).not.toHaveBeenCalled(); }); - test('ensures the producer is used for authorization if the consumer is `alerts`', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - + it('authorized correctly', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'alerts', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "myType/myApp/rule/create", + ], + }, + ] + `); + }); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' + it('throws if user lacks the required rule privileges for the consumer', async () => { + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue( + jest.fn(async () => ({ hasAllRequested: false })) ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); - test('throws if user lacks the required rule privileges for the consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), - authorized: true, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to create \\"myType\\" rule"` + `"Unauthorized by \\"myApp\\" to create \\"myType\\" rule"` ); }); - test('throws if user lacks the required alert privileges for the consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws if user lacks the required alert privileges for the consumer', async () => { + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue( + jest.fn(async () => ({ hasAllRequested: false })) + ); + const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myType', 'myAppRulesOnly', 'alert', 'update'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myAppRulesOnly', + consumer: 'myApp', operation: WriteOperations.Update, entity: AlertingAuthorizationEntity.Alert, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myAppRulesOnly\\" to update \\"myType\\" alert"` + `"Unauthorized by \\"myApp\\" to update \\"myType\\" alert"` ); }); - test('throws if user lacks the required privileges for the producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws if the user has access but the consumer is not registered', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + consumer: 'not-exist', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to update \\"myType\\" alert"` + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` ); }); - test('throws if user lacks the required privileges for both consumer and producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws when there is no authorization api but the consumer is not registered', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'create'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'not-exist', operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Alert, + entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to create \\"myType\\" alert"` + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` ); }); - test('checks additional privileges correctly', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws when the security license is disabled but the consumer is not registered', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - additionalPrivileges: ['test/create'], - }); + await expect( + alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'not-exist', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` + ); + }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error when the consumer does not exist because it was from a disabled plugin', async () => { + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['disabled-feature-consumer'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['enabled-feature-consumer'] }, + ]), + ]); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), 'test/create'], + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: ['my-feature-1'], }); - }); - }); - describe('getFindAuthorizationFilter', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const mySecondAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType, mySecondAppAlertType]); - test('omits filter when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, ruleTypeRegistry, - features, - getSpace, getSpaceId, - }); - const { filter, ensureRuleTypeIsAuthorized } = - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - }); - expect(() => ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule')).not.toThrow(); - expect(filter).toEqual(undefined); - }); - test('ensureRuleTypeIsAuthorized is no-op when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - } + + await expect( + auth.ensureAuthorized({ + ruleTypeId: 'rule-type-1', + consumer: 'disabled-feature-consumer', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"disabled-feature-consumer\\" to create \\"rule-type-1\\" rule"` ); - ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule'); }); - test('creates a filter based on the privileged types', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myAppAlertType', 'mySecondAppAlertType']), - mockFeature('alerts', 'myOtherAppAlertType'), - myOtherAppFeature, - myAppWithSubFeature, - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + + it('checks additional privileges correctly', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; + await alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'myApp', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + additionalPrivileges: ['test/create'], + }); - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: mySecondAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` - ); + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "myType/myApp/rule/create", + "test/create", + ], + }, + ] + `); }); - test('throws if user has no privileges to any rule type', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), - authorized: false, - }, - ], - }, - }); - const alertAuthorization = new AlertingAuthorization({ + }); + + describe('getFindAuthorizationFilter', () => { + it('creates a filter based on the privileged types', async () => { + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized to find rules for any rule types"` - ); - }); - test('creates an `ensureRuleTypeIsAuthorized` function which throws if type is unauthorized', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', ['myOtherAppAlertType', 'myAppAlertType']), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'alerts', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'find' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'find'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'find'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-2', 'alerts', 'rule', 'find'), + authorized: true, }, - ], - }, - }); - const alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - } - ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'alert'); - }).toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to find \\"myAppAlertType\\" alert"` - ); - }); - test('creates an `ensureRuleTypeIsAuthorized` function which is no-op if type is authorized', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', 'myAppAlertType'), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'find'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-3', 'alerts', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'find'), - authorized: true, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-d', 'rule', 'find'), + authorized: false, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', + + const filter = ( + await auth.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + }, }, - } + }) + ).filter; + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/find", + "rule-type-id-1/consumer-a/rule/find", + "rule-type-id-1/consumer-b/rule/find", + "rule-type-id-2/alerts/rule/find", + "rule-type-id-2/consumer-b/rule/find", + "rule-type-id-3/alerts/rule/find", + "rule-type-id-3/consumer-c/rule/find", + "rule-type-id-4/consumer-d/rule/find", + ], + }, + ] + `); + + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"((path.to.rule_type_id: rule-type-id-1 AND (consumer-field: alerts OR consumer-field: consumer-a OR consumer-field: consumer-b)) OR (path.to.rule_type_id: rule-type-id-2 AND (consumer-field: alerts OR consumer-field: consumer-b)) OR (path.to.rule_type_id: rule-type-id-3 AND (consumer-field: consumer-c OR consumer-field: alerts)))"` ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - }).not.toThrow(); }); - test('creates an `logSuccessfulAuthorization` function which logs every authorized type', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType', 'mySecondAppAlertType']), - mockFeature('myOtherApp', ['mySecondAppAlertType', 'myAppAlertType']), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + + it('does not throw if the rule type is authorized', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('mySecondAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'mySecondAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'find'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { + + const { ensureRuleTypeIsAuthorized } = await auth.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - } - ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - ensureRuleTypeIsAuthorized('mySecondAppAlertType', 'myOtherApp', 'rule'); - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - }).not.toThrow(); + }, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'rule') + ).not.toThrow(); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-b', 'rule') + ).not.toThrow(); }); + }); - // This is a specific use case currently for alerts as data - // Space ids are stored in the alerts documents and even if security is disabled - // still need to consider the users space privileges - test('creates a spaceId only filter if security is disabled, but require space awareness', async () => { - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, + describe('getAuthorizationFilter', () => { + describe('filter', () => { + it('gets the filter correctly with no security and no spaceIds in the fields names', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(filter).toEqual(undefined); }); - const { filter } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { - type: AlertingAuthorizationFilterType.ESDSL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - spaceIds: 'path.to.space.id', + + // This is a specific use case currently for alerts as data + // Space ids are stored in the alerts documents and even if security is disabled + // still need to consider the users space privileges + it('gets the filter correctly with no security and spaceIds in the fields names', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + spaceIds: 'path.to.space.id', + }, }, - } - ); + operation: ReadOperations.Get, + }); - expect(filter).toEqual({ - bool: { minimum_should_match: 1, should: [{ match: { 'path.to.space.id': 'space1' } }] }, + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"path.to.space.id: space1"` + ); }); - }); - }); - describe('filterByRuleTypeAuthorization', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'myOtherApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType]); - beforeEach(() => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', ['myAppAlertType', 'myOtherAppAlertType']), - ]); - }); - test('augments a list of types with all features when there is no authorization api', async () => { - features.getKibanaFeatures.mockReturnValue([ - myAppFeature, - myOtherAppFeature, - myAppWithSubFeature, - myFeatureWithoutAlerting, - ]); - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, + it('gets the filter correctly with security disabled', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(filter).toEqual(undefined); }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "alerts": Object { - "all": true, - "read": true, + it('gets the filter correctly for all rule types and consumers', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "discover": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myAppWithSubFeature": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'get'), + authorized: true, }, - "myOtherApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-4', 'consumer-d', 'rule', 'get'), + authorized: true, }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "alerts": Object { - "all": true, - "read": true, + operation: ReadOperations.Get, + }); + + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"((ruleId: rule-type-id-1 AND (consumer: consumer-a OR consumer: consumer-b)) OR (ruleId: rule-type-id-2 AND consumer: consumer-b) OR (ruleId: rule-type-id-3 AND consumer: consumer-c) OR (ruleId: rule-type-id-4 AND consumer: consumer-d))"` + ); + }); + + it('throws when the user is not authorized for any rule type', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await expect( + auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "discover": Object { - "all": true, - "read": true, + }, + operation: ReadOperations.Get, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized to get rules for any rule types"` + ); + }); + }); + + describe('ensureRuleTypeIsAuthorized', () => { + it('does not throw if the rule type is authorized', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "myApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myAppWithSubFeature": Object { - "all": true, - "read": true, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'rule') + ).not.toThrow(); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-b', 'rule') + ).not.toThrow(); + }); + + it('throws if the rule type is not authorized', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "myOtherApp": Object { - "all": true, - "read": true, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-a', 'rule') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-a\\" to get \\"rule-type-id-2\\" rule"` + ); + }); + + it('throws if the rule type is not authorized for the entity', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'alert') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-a\\" to get \\"rule-type-id-1\\" alert"` + ); + }); + + it('throws if the rule type is not authorized for the consumer', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - } + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-b', 'rule') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-b\\" to get \\"rule-type-id-1\\" rule"` + ); + }); + }); + }); + + describe('getAuthorizedRuleTypes', () => { + it('calls checkPrivileges correctly', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await auth.getAuthorizedRuleTypes({ + ruleTypeIds: ['rule-type-id-1'], + operations: [WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/create", + ], + }, + ] `); }); - test('augments a list of types with consumers under which the operation is authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('returns the authorized rules correctly', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'create' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, + expect( + await auth.getAuthorizedRuleTypes({ + ruleTypeIds: ['rule-type-id-1'], + operations: [WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Map { + "rule-type-id-1" => Object { "authorizedConsumers": Object { - "myApp": Object { + "consumer-a": Object { "all": true, "read": true, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": true, - "read": true, + } + `); + }); + }); + + describe('getAllAuthorizedRuleTypes', () => { + it('get authorized rule types with authorized consumers', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), + authorized: false, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + await auth.getAllAuthorizedRuleTypes({ + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "consumer-b": Object { + "all": false, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('calls checkPrivileges with the correct actions', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await auth.getAllAuthorizedRuleTypes({ + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/get", + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/get", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/get", + "rule-type-id-1/consumer-b/rule/create", + "rule-type-id-2/alerts/rule/get", + "rule-type-id-2/alerts/rule/create", + "rule-type-id-2/consumer-b/rule/get", + "rule-type-id-2/consumer-b/rule/create", + "rule-type-id-3/alerts/rule/get", + "rule-type-id-3/alerts/rule/create", + "rule-type-id-3/consumer-c/rule/get", + "rule-type-id-3/consumer-c/rule/create", + "rule-type-id-4/consumer-d/rule/get", + "rule-type-id-4/consumer-d/rule/create", + ], + }, + ] + `); + }); + }); + + describe('_getAuthorizedRuleTypesWithAuthorizedConsumers', () => { + it('returns all rule types with all consumers as authorized with no authorization', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-4" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('filters out rule types with no authorization', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('returns all rule types with all consumers as authorized with disabled authorization', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-4" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('filters out rule types with disabled authorization', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('get authorized rule types with authorized consumers with read access only', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": false, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('get authorized rule types with authorized consumers with full access', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('filters out not requested rule types', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'create'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": false, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('authorizes user under the `alerts` consumer when they are authorized by the producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('returns an empty map with no requested rule types', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('augments a list of types with consumers under which multiple operations are authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('get authorized rule types with authorized consumers when some rule types are not authorized', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'create' - ), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'get'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'get' - ), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'get'), - authorized: true, + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'create'), + authorized: false, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'get'), + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create, ReadOperations.Get], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": false, - "read": true, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": false, - "read": true, - }, - "myOtherApp": Object { - "all": false, - "read": true, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "consumer-c": Object { + "all": false, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('omits types which have no consumers under which the operation is authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('get authorized rule types with authorized consumers when consumers are not valid for a rule type', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'create' - ), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'create'), authorized: false, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-d', 'rule', 'get'), + authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": true, - "read": true, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - }); - describe('getAugmentedRuleTypesWithAuthorization', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: true, - hasFieldsForAAD: true, - validLegacyConsumers: [], - }; - const mySecondAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType, mySecondAppAlertType]); - beforeEach(() => { - features.getKibanaFeatures.mockReturnValue([mockFeature('myApp', ['myOtherAppAlertType'])]); - }); - test('it returns authorized rule types given a set of feature ids', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('filters out rule types that are not in the rule type registry but registered in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => false); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getAugmentedRuleTypesWithAuthorization( - ['myApp'], - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['rule-type-id-1'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` Object { - "authorizedRuleTypes": Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": false, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "alerts", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - }, - "hasAllRequested": false, + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, "username": "some-user", } `); }); - test('it returns all authorized if user has read, get and update alert privileges', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('filters out rule types that are registered in the rule type registry but not in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => true); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'get'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'update'), + privilege: mockAuthorizationAction('not-exist', 'consumer-a', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getAugmentedRuleTypesWithAuthorization( - ['myApp'], - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` Object { - "authorizedRuleTypes": Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "alerts", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - }, - "hasAllRequested": false, + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, "username": "some-user", } `); }); - }); - describe('8.11+', () => { - let alertAuthorization: AlertingAuthorization; - - const setOfRuleTypes: RegistryRuleType[] = [ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.esQuery', - name: 'ES Query', - category: 'management', - producer: 'stackAlerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['discover', 'alerts'], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.threshold-rule-o11y', - name: 'New threshold 011y', - category: 'observability', - producer: 'observability', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.infrastructure-threshold-o11y', - name: 'Metrics o11y', - category: 'observability', - producer: 'infrastructure', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['alerts'], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.logs-threshold-o11y', - name: 'Logs o11y', - category: 'observability', - producer: 'logs', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['alerts'], - }, - ]; + it('call checkPrivileges with the correct actions', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); - const onlyStackAlertsKibanaPrivileges = [ - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'find'), - authorized: true, - }, - ]; - const only011yKibanaPrivileges = [ - { - privilege: mockAuthorizationAction( - '.infrastructure-threshold-o11y', - 'infrastructure', - 'rule', - 'create' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.infrastructure-threshold-o11y', - 'infrastructure', - 'rule', - 'find' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.threshold-rule-o11y', - 'infrastructure', - 'rule', - 'create' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.threshold-rule-o11y', - 'infrastructure', - 'rule', - 'find' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - ]; - const onlyLogsAndStackAlertsKibanaPrivileges = [ - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - ]; - - beforeEach(async () => { - ruleTypeRegistry.list.mockReturnValue(new Set(setOfRuleTypes)); - ruleTypeRegistry.get.mockImplementation((id: string) => { - if (setOfRuleTypes.some((rt) => rt.id === id)) { - const ruleType = setOfRuleTypes.find((rt) => rt.id === id); - return (ruleType ?? {}) as NormalizedRuleType<{}, {}, {}, {}, {}, '', '', {}>; - } - return {} as NormalizedRuleType<{}, {}, {}, {}, {}, '', '', {}>; + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [...ruleTypeIds, 'rule-type-not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); - }); - describe('user only access to stack alerts + discover', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockReset(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('stackAlerts', ['.esQuery']), - mockFeature('discover', []), - ]); - checkPrivileges.mockReset(); - checkPrivileges.mockResolvedValue({ - username: 'onlyStack', - hasAllRequested: true, - privileges: { - kibana: onlyStackAlertsKibanaPrivileges, + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/get", + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/get", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/get", + "rule-type-id-1/consumer-b/rule/create", + "rule-type-id-2/alerts/rule/get", + "rule-type-id-2/alerts/rule/create", + "rule-type-id-2/consumer-b/rule/get", + "rule-type-id-2/consumer-b/rule/create", + "rule-type-id-3/alerts/rule/get", + "rule-type-id-3/alerts/rule/create", + "rule-type-id-3/consumer-c/rule/get", + "rule-type-id-3/consumer-c/rule/create", + "rule-type-id-4/consumer-d/rule/get", + "rule-type-id-4/consumer-d/rule/create", + ], }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReset(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); + ] + `); + }); - describe('ensureAuthorized', () => { - test('should allow to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); + it('call checkPrivileges with the correct actions when the rule type does not exist in the registry', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => false); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"logs\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with infrastructure consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .logs-threshold-o11y rule type with alerts infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".logs-threshold-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, }); - test('creates a filter based on the privileged types', async () => { - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"(path.to.rule_type_id: .esQuery AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts))"` - ); + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['rule-type-id-1'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); - }); - describe('user only access to o11y', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockReset(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('infrastructure', [ - '.infrastructure-threshold-o11y', - '.threshold-rule-o11y', - '.esQuery', - ]), - mockFeature('logs', ['.threshold-rule-o11y', '.esQuery', '.logs-threshold-o11y']), - ]); - checkPrivileges.mockReset(); - checkPrivileges.mockResolvedValue({ - username: 'onlyO11y', - hasAllRequested: true, - privileges: { - kibana: only011yKibanaPrivileges, + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [], }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReset(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); - - describe('ensureAuthorized', () => { - test('should throw an error to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"stackAlerts\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"discover\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .logs-threshold-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - }); - test('creates a filter based on the privileged types', async () => { - expect( - ( - await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - new Set(['infrastructure', 'logs']) - ) - ).filter - ).toEqual( - fromKueryExpression( - `(path.to.rule_type_id:.infrastructure-threshold-o11y and consumer-field:(infrastructure or alerts)) or (path.to.rule_type_id:.threshold-rule-o11y and consumer-field:(infrastructure or logs)) or (path.to.rule_type_id:.logs-threshold-o11y and consumer-field:(logs or alerts))` - ) - ); - }); + ] + `); }); - describe('user only access to logs and stackAlerts', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockClear(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('stackAlerts', ['.esQuery']), - mockFeature('logs', ['.logs-threshold-o11y', '.threshold-rule-o11y', '.esQuery']), - ]); - checkPrivileges.mockClear(); - checkPrivileges.mockResolvedValue({ - username: 'stackAndLogs', - hasAllRequested: true, - privileges: { - kibana: onlyLogsAndStackAlertsKibanaPrivileges, - }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); - - describe('ensureAuthorized', () => { - test('should allow to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); + it('call checkPrivileges with the correct actions when the rule type does not exist in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => true); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .logs-threshold-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with logs infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with infrastructure consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, }); - test('creates a filter based on the privileged types', async () => { - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; - - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"((path.to.rule_type_id: .esQuery AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)) OR (path.to.rule_type_id: .logs-threshold-o11y AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)) OR (path.to.rule_type_id: .threshold-rule-o11y AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)))"` - ); + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts index 6b24f2f5de9a4..a7e36590d2217 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts @@ -6,61 +6,20 @@ */ import Boom from '@hapi/boom'; -import { has, isEmpty } from 'lodash'; import { KibanaRequest } from '@kbn/core/server'; import { JsonObject } from '@kbn/utility-types'; import { KueryNode } from '@kbn/es-query'; -import { SecurityPluginSetup } from '@kbn/security-plugin/server'; +import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; -import { STACK_ALERTS_FEATURE_ID } from '@kbn/rule-data-utils'; import { RegistryRuleType } from '../rule_type_registry'; -import { ALERTING_FEATURE_ID, RuleTypeRegistry } from '../types'; +import { RuleTypeRegistry } from '../types'; import { asFiltersByRuleTypeAndConsumer, asFiltersBySpaceId, AlertingAuthorizationFilterOpts, } from './alerting_authorization_kuery'; - -export enum AlertingAuthorizationEntity { - Rule = 'rule', - Alert = 'alert', -} - -export enum ReadOperations { - Get = 'get', - GetRuleState = 'getRuleState', - GetAlertSummary = 'getAlertSummary', - GetExecutionLog = 'getExecutionLog', - GetActionErrorLog = 'getActionErrorLog', - Find = 'find', - GetAuthorizedAlertsIndices = 'getAuthorizedAlertsIndices', - GetRuleExecutionKPI = 'getRuleExecutionKPI', - GetBackfill = 'getBackfill', - FindBackfill = 'findBackfill', -} - -export enum WriteOperations { - Create = 'create', - Delete = 'delete', - Update = 'update', - UpdateApiKey = 'updateApiKey', - Enable = 'enable', - Disable = 'disable', - MuteAll = 'muteAll', - UnmuteAll = 'unmuteAll', - MuteAlert = 'muteAlert', - UnmuteAlert = 'unmuteAlert', - Snooze = 'snooze', - BulkEdit = 'bulkEdit', - BulkDelete = 'bulkDelete', - BulkEnable = 'bulkEnable', - BulkDisable = 'bulkDisable', - Unsnooze = 'unsnooze', - RunSoon = 'runSoon', - ScheduleBackfill = 'scheduleBackfill', - DeleteBackfill = 'deleteBackfill', -} +import { ReadOperations, WriteOperations, AlertingAuthorizationEntity } from './types'; export interface EnsureAuthorizedOpts { ruleTypeId: string; @@ -74,75 +33,178 @@ interface HasPrivileges { read: boolean; all: boolean; } + type AuthorizedConsumers = Record; export interface RegistryAlertTypeWithAuth extends RegistryRuleType { authorizedConsumers: AuthorizedConsumers; } -type IsAuthorizedAtProducerLevel = boolean; -export interface ConstructorOptions { +export type AuthorizedRuleTypes = Map; + +export interface CreateOptions { ruleTypeRegistry: RuleTypeRegistry; request: KibanaRequest; features: FeaturesPluginStart; getSpace: (request: KibanaRequest) => Promise; getSpaceId: (request: KibanaRequest) => string | undefined; - authorization?: SecurityPluginSetup['authz']; + authorization?: SecurityPluginStart['authz']; +} + +type ConstructorOptions = Pick< + CreateOptions, + 'ruleTypeRegistry' | 'request' | 'authorization' | 'getSpaceId' +> & { + allRegisteredConsumers: Set; + ruleTypesConsumersMap: Map>; +}; + +interface GetAuthorizationFilterParams { + authorizationEntity: AlertingAuthorizationEntity; + filterOpts: AlertingAuthorizationFilterOpts; + operation: WriteOperations | ReadOperations; } -const DISCOVER_FEATURE_ID = 'discover'; +interface GetAuthorizedRuleTypesWithAuthorizedConsumersParams { + ruleTypeIds?: string[]; + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} + +interface GetAllAuthorizedRuleTypesFindOperationParams { + authorizationEntity: AlertingAuthorizationEntity; + ruleTypeIds?: string[]; +} + +interface GetFindAuthorizationFilterParams { + authorizationEntity: AlertingAuthorizationEntity; + filterOpts: AlertingAuthorizationFilterOpts; +} + +interface GetAuthorizedRuleTypesParams { + ruleTypeIds?: string[]; + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} + +interface GetAllAuthorizedRuleTypes { + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} export class AlertingAuthorization { private readonly ruleTypeRegistry: RuleTypeRegistry; private readonly request: KibanaRequest; - private readonly authorization?: SecurityPluginSetup['authz']; - private readonly featuresIds: Promise>; - private readonly allPossibleConsumers: Promise; + private readonly authorization?: SecurityPluginStart['authz']; + private readonly allRegisteredConsumers: Set; + private readonly ruleTypesConsumersMap: Map>; private readonly spaceId: string | undefined; - private readonly features: FeaturesPluginStart; + constructor({ ruleTypeRegistry, request, authorization, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }: ConstructorOptions) { this.request = request; this.authorization = authorization; this.ruleTypeRegistry = ruleTypeRegistry; - this.features = features; + this.allRegisteredConsumers = allRegisteredConsumers; + this.ruleTypesConsumersMap = ruleTypesConsumersMap; this.spaceId = getSpaceId(request); + } - this.featuresIds = getSpace(request) - .then((maybeSpace) => new Set(maybeSpace?.disabledFeatures ?? [])) - .then( - (disabledFeatures) => - new Set( - features - .getKibanaFeatures() - .filter( - ({ id, alerting }) => - // ignore features which are disabled in the user's space - !disabledFeatures.has(id) && - // ignore features which don't grant privileges to alerting - (alerting?.length ?? 0 > 0) - ) - .map((feature) => feature.id) - ) - ) - .catch(() => { - // failing to fetch the space means the user is likely not privileged in the - // active space at all, which means that their list of features should be empty - return new Set(); - }); + /** + * Creates an AlertingAuthorization object. + */ + static async create({ + request, + features, + getSpace, + getSpaceId, + authorization, + ruleTypeRegistry, + }: CreateOptions): Promise { + const allRegisteredConsumers = new Set(); + const ruleTypesConsumersMap = new Map>(); + let maybeSpace; + + try { + maybeSpace = await getSpace(request); + } catch (error) { + /** + * Failing to fetch the space with 403 or 404 means the user is likely not privileged in the active space at all + * which means that `allRegisteredConsumers` and `ruleTypesConsumersMap` should be empty. By initializing the alerting authorization + * with empty data structures we ensure that the user will not have access to any rule types in the active space. + * All other errors are treated as server errors and they are surfaced to the upper level. + */ + if (Boom.isBoom(error) && [403, 404].includes(error.output.statusCode)) { + return new AlertingAuthorization({ + request, + authorization, + getSpaceId, + ruleTypeRegistry, + allRegisteredConsumers, + ruleTypesConsumersMap, + }); + } + + if (Boom.isBoom(error)) { + throw error; + } - this.allPossibleConsumers = this.featuresIds.then((featuresIds) => { - return featuresIds.size - ? asAuthorizedConsumers([ALERTING_FEATURE_ID, DISCOVER_FEATURE_ID, ...featuresIds], { - read: true, - all: true, - }) - : {}; + throw new Error(`Failed to create AlertingAuthorization class: ${error}`); + } + + const disabledFeatures = new Set(maybeSpace?.disabledFeatures ?? []); + const featuresWithAlertingConfigured = features.getKibanaFeatures().filter( + ({ id, alerting }) => + // ignore features which are disabled in the user's space + !disabledFeatures.has(id) && + // ignore features which don't grant privileges to alerting + Boolean(alerting?.length) + ); + + /** + * Each feature configures a set of rule types. Each + * rule type configures its valid consumers. For example, + * + * { id: 'my-feature-id-1', alerting: [{ ruleTypeId: 'my-rule-type', consumers: ['consumer-a', 'consumer-b'] }] } + * { id: 'my-feature-id-2', alerting: [{ ruleTypeId: 'my-rule-type-2', consumers: ['consumer-a', 'consumer-d'] }] } + * + * In this loop we iterate over all features and we construct: + * a) a set that contains all registered consumers and + * b) a map that contains all valid consumers per rule type. + * We remove duplicates in the process. For example, + * + * allRegisteredConsumers: Set(1) { 'consumer-a', 'consumer-b', 'consumer-d' } + * ruleTypesConsumersMap: Map(1) { + * 'my-rule-type' => Set(1) { 'consumer-a', 'consumer-b' } + * 'my-rule-type-2' => Set(1) { 'consumer-a', 'consumer-d' } + * } + */ + for (const feature of featuresWithAlertingConfigured) { + if (feature.alerting) { + for (const entry of feature.alerting) { + const consumers = ruleTypesConsumersMap.get(entry.ruleTypeId) ?? new Set(); + + entry.consumers.forEach((consumer) => { + consumers.add(consumer); + allRegisteredConsumers.add(consumer); + }); + ruleTypesConsumersMap.set(entry.ruleTypeId, consumers); + } + } + } + + return new AlertingAuthorization({ + request, + authorization, + getSpaceId, + ruleTypeRegistry, + allRegisteredConsumers, + ruleTypesConsumersMap, }); } @@ -155,42 +217,30 @@ export class AlertingAuthorization { } /* - * This method exposes the private 'augmentRuleTypesWithAuthorization' to be + * This method exposes the private '_getAuthorizedRuleTypesWithAuthorizedConsumers' to be * used by the RAC/Alerts client */ - public async getAugmentedRuleTypesWithAuthorization( - featureIds: readonly string[], - operations: Array, - authorizationEntity: AlertingAuthorizationEntity - ): Promise<{ + public async getAllAuthorizedRuleTypes(params: GetAllAuthorizedRuleTypes): Promise<{ username?: string; hasAllRequested: boolean; - authorizedRuleTypes: Set; + authorizedRuleTypes: AuthorizedRuleTypes; }> { - return this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - operations, - authorizationEntity, - new Set(featureIds) - ); + return this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + operations: params.operations, + authorizationEntity: params.authorizationEntity, + }); } public async ensureAuthorized({ ruleTypeId, - consumer: legacyConsumer, + consumer, operation, entity, additionalPrivileges = [], }: EnsureAuthorizedOpts) { const { authorization } = this; - const ruleType = this.ruleTypeRegistry.get(ruleTypeId); - const consumer = getValidConsumer({ - validLegacyConsumers: ruleType.validLegacyConsumers, - legacyConsumer, - producer: ruleType.producer, - }); - const isAvailableConsumer = has(await this.allPossibleConsumers, consumer); + const isAvailableConsumer = this.allRegisteredConsumers.has(consumer); if (authorization && this.shouldCheckAuthorization()) { const checkPrivileges = authorization.checkPrivilegesDynamicallyWithRequest(this.request); @@ -209,7 +259,7 @@ export class AlertingAuthorization { * as Privileged. * This check will ensure we don't accidentally let these through */ - throw Boom.forbidden(getUnauthorizedMessage(ruleTypeId, legacyConsumer, operation, entity)); + throw Boom.forbidden(getUnauthorizedMessage(ruleTypeId, consumer, operation, entity)); } if (!hasAllRequested) { @@ -220,274 +270,204 @@ export class AlertingAuthorization { } } - public async getFindAuthorizationFilter( - authorizationEntity: AlertingAuthorizationEntity, - filterOpts: AlertingAuthorizationFilterOpts, - featuresIds?: Set - ): Promise<{ + public async getFindAuthorizationFilter(params: GetFindAuthorizationFilterParams): Promise<{ filter?: KueryNode | JsonObject; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }> { - return this.getAuthorizationFilter( - authorizationEntity, - filterOpts, - ReadOperations.Find, - featuresIds - ); + return this.getAuthorizationFilter({ + operation: ReadOperations.Find, + authorizationEntity: params.authorizationEntity, + filterOpts: params.filterOpts, + }); } - public async getAuthorizedRuleTypes( - authorizationEntity: AlertingAuthorizationEntity, - featuresIds?: Set - ): Promise { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - [ReadOperations.Find], - authorizationEntity, - featuresIds - ); - return Array.from(authorizedRuleTypes); + public async getAllAuthorizedRuleTypesFindOperation( + params: GetAllAuthorizedRuleTypesFindOperationParams + ): Promise { + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: params.ruleTypeIds, + operations: [ReadOperations.Find], + authorizationEntity: params.authorizationEntity, + }); + + return authorizedRuleTypes; } - public async getAuthorizationFilter( - authorizationEntity: AlertingAuthorizationEntity, - filterOpts: AlertingAuthorizationFilterOpts, - operation: WriteOperations | ReadOperations, - featuresIds?: Set - ): Promise<{ + public async getAuthorizationFilter(params: GetAuthorizationFilterParams): Promise<{ filter?: KueryNode | JsonObject; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }> { if (this.authorization && this.shouldCheckAuthorization()) { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - [operation], - authorizationEntity, - featuresIds - ); + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + operations: [params.operation], + authorizationEntity: params.authorizationEntity, + }); if (!authorizedRuleTypes.size) { - throw Boom.forbidden(`Unauthorized to find ${authorizationEntity}s for any rule types`); + throw Boom.forbidden( + `Unauthorized to ${params.operation} ${params.authorizationEntity}s for any rule types` + ); } - const authorizedRuleTypeIdsToConsumers = new Set( - [...authorizedRuleTypes].reduce((ruleTypeIdConsumerPairs, ruleType) => { - for (const consumer of Object.keys(ruleType.authorizedConsumers)) { - ruleTypeIdConsumerPairs.push(`${ruleType.id}/${consumer}/${authorizationEntity}`); - } - return ruleTypeIdConsumerPairs; - }, []) - ); - - const authorizedEntries: Map> = new Map(); return { filter: asFiltersByRuleTypeAndConsumer( authorizedRuleTypes, - filterOpts, + params.filterOpts, this.spaceId ) as JsonObject, ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, authType: string) => { - if (!authorizedRuleTypeIdsToConsumers.has(`${ruleTypeId}/${consumer}/${authType}`)) { + if (!authorizedRuleTypes.has(ruleTypeId) || authType !== params.authorizationEntity) { + throw Boom.forbidden( + getUnauthorizedMessage(ruleTypeId, consumer, params.operation, authType) + ); + } + + const authorizedRuleType = authorizedRuleTypes.get(ruleTypeId)!; + const authorizedConsumers = authorizedRuleType.authorizedConsumers; + + if (!authorizedConsumers[consumer]) { throw Boom.forbidden( - getUnauthorizedMessage(ruleTypeId, consumer, 'find', authorizationEntity) + getUnauthorizedMessage( + ruleTypeId, + consumer, + params.operation, + params.authorizationEntity + ) ); - } else { - if (authorizedEntries.has(ruleTypeId)) { - authorizedEntries.get(ruleTypeId)!.add(consumer); - } else { - authorizedEntries.set(ruleTypeId, new Set([consumer])); - } } }, }; } return { - filter: asFiltersBySpaceId(filterOpts, this.spaceId) as JsonObject, + filter: asFiltersBySpaceId(params.filterOpts, this.spaceId) as JsonObject, ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, authType: string) => {}, }; } - public async filterByRuleTypeAuthorization( - ruleTypes: Set, - operations: Array, - authorizationEntity: AlertingAuthorizationEntity - ): Promise> { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - ruleTypes, - operations, - authorizationEntity - ); + public async getAuthorizedRuleTypes( + params: GetAuthorizedRuleTypesParams + ): Promise { + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: params.ruleTypeIds, + operations: params.operations, + authorizationEntity: params.authorizationEntity, + }); + return authorizedRuleTypes; } - private async augmentRuleTypesWithAuthorization( - ruleTypes: Set, - operations: Array, - authorizationEntity: AlertingAuthorizationEntity, - featuresIds?: Set + private async _getAuthorizedRuleTypesWithAuthorizedConsumers( + params: GetAuthorizedRuleTypesWithAuthorizedConsumersParams ): Promise<{ username?: string; hasAllRequested: boolean; - authorizedRuleTypes: Set; + authorizedRuleTypes: Map; }> { - const fIds = new Set(featuresIds ?? (await this.featuresIds)); + const { operations, authorizationEntity } = params; + const ruleTypeIds = params.ruleTypeIds + ? new Set(params.ruleTypeIds) + : new Set(this.ruleTypeRegistry.getAllTypes()); - /** - * Temporary hack to fix issues with the discover consumer. - * Issue: https://github.com/elastic/kibana/issues/184595. - * PR https://github.com/elastic/kibana/pull/183756 will - * remove the hack and fix it in a generic way. - * - * The discover consumer should be authorized - * as the stackAlerts consumer. - */ - if (fIds.has(DISCOVER_FEATURE_ID)) { - fIds.delete(DISCOVER_FEATURE_ID); - fIds.add(STACK_ALERTS_FEATURE_ID); - } + const requiredPrivileges = new Map< + string, + { ruleTypeId: string; consumer: string; operation: ReadOperations | WriteOperations } + >(); if (this.authorization && this.shouldCheckAuthorization()) { + const authorizedRuleTypes = new Map(); + const checkPrivileges = this.authorization.checkPrivilegesDynamicallyWithRequest( this.request ); - // add an empty `authorizedConsumers` array on each ruleType - const ruleTypesWithAuthorization = Array.from( - this.augmentWithAuthorizedConsumers(ruleTypes, {}) - ); - const ruleTypesAuthorized: Map = new Map(); - // map from privilege to ruleType which we can refer back to when analyzing the result - // of checkPrivileges - const privilegeToRuleType = new Map< - string, - [RegistryAlertTypeWithAuth, string, HasPrivileges, IsAuthorizedAtProducerLevel] - >(); - const allPossibleConsumers = await this.allPossibleConsumers; - const addLegacyConsumerPrivileges = (legacyConsumer: string) => - legacyConsumer === ALERTING_FEATURE_ID || - legacyConsumer === DISCOVER_FEATURE_ID || - isEmpty(featuresIds); - - for (const feature of fIds) { - const featureDef = this.features - .getKibanaFeatures() - .find((kFeature) => kFeature.id === feature); - - for (const ruleTypeId of featureDef?.alerting ?? []) { - const ruleTypeAuth = ruleTypesWithAuthorization.find((rtwa) => rtwa.id === ruleTypeId); - if (ruleTypeAuth) { - if (!ruleTypesAuthorized.has(ruleTypeId)) { - ruleTypesAuthorized.set(ruleTypeId, ruleTypeAuth); - } - for (const operation of operations) { - privilegeToRuleType.set( - this.authorization!.actions.alerting.get( - ruleTypeId, - feature, - authorizationEntity, - operation - ), - [ - ruleTypeAuth, - feature, - hasPrivilegeByOperation(operation), - ruleTypeAuth.producer === feature, - ] - ); - // FUTURE ENGINEER - // We are just trying to add back the legacy consumers associated - // to the rule type to get back the privileges that was given at one point - if (!isEmpty(ruleTypeAuth.validLegacyConsumers)) { - ruleTypeAuth.validLegacyConsumers.forEach((legacyConsumer) => { - if (addLegacyConsumerPrivileges(legacyConsumer)) { - if (!allPossibleConsumers[legacyConsumer]) { - allPossibleConsumers[legacyConsumer] = { - read: true, - all: true, - }; - } - - privilegeToRuleType.set( - this.authorization!.actions.alerting.get( - ruleTypeId, - legacyConsumer, - authorizationEntity, - operation - ), - [ruleTypeAuth, legacyConsumer, hasPrivilegeByOperation(operation), false] - ); - } - }); + for (const ruleTypeId of ruleTypeIds) { + /** + * Skip if the ruleTypeId is not configured in any feature + * or it is not set in the rule type registry. + */ + if (!this.ruleTypesConsumersMap.has(ruleTypeId) || !this.ruleTypeRegistry.has(ruleTypeId)) { + continue; + } + + const ruleType = this.ruleTypeRegistry.get(ruleTypeId)!; + const ruleTypeConsumers = this.ruleTypesConsumersMap.get(ruleTypeId) ?? new Set(); + + for (const consumerToAuthorize of ruleTypeConsumers) { + for (const operation of operations) { + requiredPrivileges.set( + this.authorization.actions.alerting.get( + ruleTypeId, + consumerToAuthorize, + authorizationEntity, + operation + ), + { + ruleTypeId: ruleType.id, + consumer: consumerToAuthorize, + operation, } - } + ); } } } const { username, hasAllRequested, privileges } = await checkPrivileges({ - kibana: [...privilegeToRuleType.keys()], + kibana: [...requiredPrivileges.keys()], }); + for (const { authorized, privilege } of privileges.kibana) { + if (authorized && requiredPrivileges.has(privilege)) { + const { ruleTypeId, consumer, operation } = requiredPrivileges.get(privilege)!; + + const authorizedRuleType = authorizedRuleTypes.get(ruleTypeId) ?? { + authorizedConsumers: {}, + }; + + const authorizedConsumers = authorizedRuleType.authorizedConsumers; + const mergedOperations = mergeHasPrivileges( + getPrivilegesFromOperation(operation), + authorizedConsumers[consumer] + ); + + authorizedRuleTypes.set(ruleTypeId, { + authorizedConsumers: { + ...authorizedConsumers, + [consumer]: mergedOperations, + }, + }); + } + } + return { username, hasAllRequested, - authorizedRuleTypes: - hasAllRequested && featuresIds === undefined - ? // has access to all features - this.augmentWithAuthorizedConsumers( - new Set(ruleTypesAuthorized.values()), - allPossibleConsumers - ) - : // only has some of the required privileges - privileges.kibana.reduce((authorizedRuleTypes, { authorized, privilege }) => { - if (authorized && privilegeToRuleType.has(privilege)) { - const [ruleType, feature, hasPrivileges, isAuthorizedAtProducerLevel] = - privilegeToRuleType.get(privilege)!; - if (fIds.has(feature)) { - ruleType.authorizedConsumers[feature] = mergeHasPrivileges( - hasPrivileges, - ruleType.authorizedConsumers[feature] - ); - - if (isAuthorizedAtProducerLevel) { - // granting privileges under the producer automatically authorized the Rules Management UI as well - ruleType.validLegacyConsumers.forEach((legacyConsumer) => { - if (addLegacyConsumerPrivileges(legacyConsumer)) { - ruleType.authorizedConsumers[legacyConsumer] = mergeHasPrivileges( - hasPrivileges, - ruleType.authorizedConsumers[legacyConsumer] - ); - } - }); - } - authorizedRuleTypes.add(ruleType); - } - } - return authorizedRuleTypes; - }, new Set()), + authorizedRuleTypes, }; } else { return { hasAllRequested: true, - authorizedRuleTypes: this.augmentWithAuthorizedConsumers( - new Set([...ruleTypes].filter((ruleType) => fIds.has(ruleType.producer))), - await this.allPossibleConsumers - ), + authorizedRuleTypes: this.getRegisteredRuleTypesWithAllRegisteredConsumers(ruleTypeIds), }; } } - private augmentWithAuthorizedConsumers( - ruleTypes: Set, - authorizedConsumers: AuthorizedConsumers - ): Set { - return new Set( - Array.from(ruleTypes).map((ruleType) => ({ - ...ruleType, - authorizedConsumers: { ...authorizedConsumers }, - })) - ); + private getRegisteredRuleTypesWithAllRegisteredConsumers(ruleTypeIds: Set) { + const authorizedRuleTypes = new Map(); + const authorizedConsumers = getConsumersWithPrivileges(this.allRegisteredConsumers, { + all: true, + read: true, + }); + + Array.from(this.ruleTypesConsumersMap.keys()) + .filter((ruleTypeId) => ruleTypeIds.has(ruleTypeId)) + .forEach((ruleTypeId) => { + authorizedRuleTypes.set(ruleTypeId, { + authorizedConsumers, + }); + }); + + return authorizedRuleTypes; } } @@ -498,7 +478,7 @@ function mergeHasPrivileges(left: HasPrivileges, right?: HasPrivileges): HasPriv }; } -function hasPrivilegeByOperation(operation: ReadOperations | WriteOperations): HasPrivileges { +function getPrivilegesFromOperation(operation: ReadOperations | WriteOperations): HasPrivileges { const read = Object.values(ReadOperations).includes(operation as unknown as ReadOperations); const all = Object.values(WriteOperations).includes(operation as unknown as WriteOperations); return { @@ -507,34 +487,21 @@ function hasPrivilegeByOperation(operation: ReadOperations | WriteOperations): H }; } -function asAuthorizedConsumers( - consumers: string[], +function getConsumersWithPrivileges( + consumers: Set, hasPrivileges: HasPrivileges ): AuthorizedConsumers { - return consumers.reduce((acc, feature) => { + return Array.from(consumers).reduce((acc, feature) => { acc[feature] = hasPrivileges; return acc; }, {}); } function getUnauthorizedMessage( - alertTypeId: string, + ruleTypeId: string, scope: string, operation: string, entity: string ): string { - return `Unauthorized by "${scope}" to ${operation} "${alertTypeId}" ${entity}`; + return `Unauthorized by "${scope}" to ${operation} "${ruleTypeId}" ${entity}`; } - -export const getValidConsumer = ({ - validLegacyConsumers, - legacyConsumer, - producer, -}: { - validLegacyConsumers: string[]; - legacyConsumer: string; - producer: string; -}): string => - legacyConsumer === ALERTING_FEATURE_ID || validLegacyConsumers.includes(legacyConsumer) - ? producer - : legacyConsumer; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts index b433a95a77734..bcc2b37dca7dd 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts @@ -5,364 +5,258 @@ * 2.0. */ -import { RecoveredActionGroup } from '../../common'; import { AlertingAuthorizationFilterType, asFiltersByRuleTypeAndConsumer, ensureFieldIsSafeForQuery, asFiltersBySpaceId, } from './alerting_authorization_kuery'; -import { fromKueryExpression } from '@kbn/es-query'; +import { KueryNode, toKqlExpression } from '@kbn/es-query'; describe('asKqlFiltersByRuleTypeAndConsumer', () => { test('constructs KQL filter for single rule type with single authorized consumer', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, - authorizedConsumers: { - myApp: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', }, - }, - 'space1' + 'space1' + ) as KueryNode ) - ).toEqual( - fromKueryExpression(`((path.to.rule_type_id:myAppAlertType and consumer-field:(myApp)))`) - ); + ).toMatchInlineSnapshot(`"(path.to.rule_type_id: myAppAlertType AND consumer-field: myApp)"`); }); test('constructs KQL filter for single rule type with multiple authorized consumers', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp)))` + 'space1' + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"(path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp))"` ); }); test('constructs KQL filter for multiple rule types across authorized consumer', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + }, + ], + [ + 'myOtherAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, + }, + ], + ]); + + expect( + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:mySecondAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)))` + 'space1' + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` ); }); test('constructs KQL filter with spaceId filter when spaceIds field path exists', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + [ + 'myOtherAppAlertType', { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.spaceIds', + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature) and path.to.spaceIds:space1) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature) and path.to.spaceIds:space1))` - ) - ); - }); + ], + ]); - test('constructs KQL filter without spaceId filter when spaceIds path is specified, but spaceId is undefined', async () => { expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.spaceIds', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + 'space1' + ) as KueryNode + ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature) AND path.to.spaceIds: space1) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature) AND path.to.spaceIds: space1))"` + ); + }); + + test('constructs KQL filter without spaceId filter when spaceIds path is specified, but spaceId is undefined', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + [ + 'myOtherAppAlertType', { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.spaceIds', + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, }, - undefined - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)))` + ], + ]); + + expect( + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.spaceIds', + }, + }, + undefined + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` ); }); test('constructs KQL filter for single rule type with no authorized consumer', async () => { - const result = asFiltersByRuleTypeAndConsumer( - new Set([ + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, authorizedConsumers: {}, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', + ], + ]); + + const result = toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + }, }, - }, - 'space1' + 'space1' + ) as KueryNode ); - expect(result).toEqual(fromKueryExpression(`path.to.rule_type_id:myAppAlertType`)); + expect(result).toMatchInlineSnapshot(`"path.to.rule_type_id: myAppAlertType"`); }); }); describe('asEsDslFiltersByRuleTypeAndConsumer', () => { test('constructs ES DSL filter for single rule type with single authorized consumer', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, - authorizedConsumers: { - myApp: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -405,30 +299,22 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }); test('constructs ES DSL filter for single rule type with multiple authorized consumers', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -478,73 +364,34 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }); test('constructs ES DSL filter for multiple rule types across authorized consumer', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + }, + ], + [ + 'myOtherAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + ]); + + expect( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -554,164 +401,175 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }, 'space1' ) - ).toEqual({ - bool: { - should: [ - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'myAppAlertType' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + ).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "path.to.rule_type_id": "myAppAlertType", + }, }, - }, - ], - minimum_should_match: 1, - }, - }, - ], - }, - }, - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'myOtherAppAlertType' } }], - minimum_should_match: 1, + ], + }, }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "alerts", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myOtherApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myAppWithSubFeature", + }, + }, + ], + }, }, - }, - ], - minimum_should_match: 1, + ], + }, }, - }, - ], + ], + }, }, - }, - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'mySecondAppAlertType' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "path.to.rule_type_id": "myOtherAppAlertType", + }, + }, + ], + }, }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "alerts", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myOtherApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myAppWithSubFeature", + }, + }, + ], + }, }, - }, - ], - minimum_should_match: 1, + ], + }, }, - }, - ], + ], + }, }, - }, - ], - minimum_should_match: 1, - }, - }); + ], + }, + } + `); }); test('constructs KQL filter for single rule type with no authorized consumer', async () => { - const result = asFiltersByRuleTypeAndConsumer( - new Set([ + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, authorizedConsumers: {}, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), + ], + ]); + + const result = asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -760,18 +618,20 @@ describe('asFiltersBySpaceId', () => { test('returns KQL filter of spaceId', () => { expect( - asFiltersBySpaceId( - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.space.id', + toKqlExpression( + asFiltersBySpaceId( + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.space.id', + }, }, - }, - 'space1' + 'space1' + ) as KueryNode ) - ).toEqual(fromKueryExpression('(path.to.space.id: space1)')); + ).toMatchInlineSnapshot(`"path.to.space.id: space1"`); }); test('returns undefined if no path to spaceIds is provided', () => { diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts index 01e30dfb38327..666059c7a7b47 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts @@ -9,7 +9,7 @@ import { remove } from 'lodash'; import { EsQueryConfig, nodeBuilder, toElasticsearchQuery, KueryNode } from '@kbn/es-query'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { RegistryAlertTypeWithAuth } from './alerting_authorization'; +import { AuthorizedRuleTypes } from './alerting_authorization'; export enum AlertingAuthorizationFilterType { KQL = 'kql', @@ -35,36 +35,39 @@ const esQueryConfig: EsQueryConfig = { }; export function asFiltersByRuleTypeAndConsumer( - ruleTypes: Set, + ruleTypes: AuthorizedRuleTypes, opts: AlertingAuthorizationFilterOpts, spaceId: string | undefined ): KueryNode | estypes.QueryDslQueryContainer { const kueryNode = nodeBuilder.or( - Array.from(ruleTypes).reduce((filters, { id, authorizedConsumers }) => { - ensureFieldIsSafeForQuery('ruleTypeId', id); - - const andNodes: KueryNode[] = [nodeBuilder.is(opts.fieldNames.ruleTypeId, id)]; - - const authorizedConsumersKeys = Object.keys(authorizedConsumers); - if (authorizedConsumersKeys.length) { - andNodes.push( - nodeBuilder.or( - authorizedConsumersKeys.map((consumer) => { - ensureFieldIsSafeForQuery('consumer', consumer); - return nodeBuilder.is(opts.fieldNames.consumer, consumer); - }) - ) - ); - } - - if (opts.fieldNames.spaceIds != null && spaceId != null) { - andNodes.push(nodeBuilder.is(opts.fieldNames.spaceIds, spaceId)); - } - - filters.push(nodeBuilder.and(andNodes)); - - return filters; - }, []) + Array.from(ruleTypes.entries()).reduce( + (filters, [id, { authorizedConsumers }]) => { + ensureFieldIsSafeForQuery('ruleTypeId', id); + + const andNodes: KueryNode[] = [nodeBuilder.is(opts.fieldNames.ruleTypeId, id)]; + + const authorizedConsumersKeys = Object.keys(authorizedConsumers); + if (authorizedConsumersKeys.length) { + andNodes.push( + nodeBuilder.or( + authorizedConsumersKeys.map((consumer) => { + ensureFieldIsSafeForQuery('consumer', consumer); + return nodeBuilder.is(opts.fieldNames.consumer, consumer); + }) + ) + ); + } + + if (opts.fieldNames.spaceIds != null && spaceId != null) { + andNodes.push(nodeBuilder.is(opts.fieldNames.spaceIds, spaceId)); + } + + filters.push(nodeBuilder.and(andNodes)); + + return filters; + }, + [] + ) ); if (opts.type === AlertingAuthorizationFilterType.ESDSL) { diff --git a/x-pack/plugins/alerting/server/authorization/index.ts b/x-pack/plugins/alerting/server/authorization/index.ts index 17f0f9f22bbe1..e31dac301cbcb 100644 --- a/x-pack/plugins/alerting/server/authorization/index.ts +++ b/x-pack/plugins/alerting/server/authorization/index.ts @@ -7,3 +7,4 @@ export * from './alerting_authorization'; export * from './alerting_authorization_kuery'; +export * from './types'; diff --git a/x-pack/plugins/alerting/server/authorization/types.ts b/x-pack/plugins/alerting/server/authorization/types.ts new file mode 100644 index 0000000000000..77357456c74b6 --- /dev/null +++ b/x-pack/plugins/alerting/server/authorization/types.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum AlertingAuthorizationEntity { + Rule = 'rule', + Alert = 'alert', +} + +export enum ReadOperations { + Get = 'get', + GetRuleState = 'getRuleState', + GetAlertSummary = 'getAlertSummary', + GetExecutionLog = 'getExecutionLog', + GetActionErrorLog = 'getActionErrorLog', + Find = 'find', + GetAuthorizedAlertsIndices = 'getAuthorizedAlertsIndices', + GetRuleExecutionKPI = 'getRuleExecutionKPI', + GetBackfill = 'getBackfill', + FindBackfill = 'findBackfill', +} + +export enum WriteOperations { + Create = 'create', + Delete = 'delete', + Update = 'update', + UpdateApiKey = 'updateApiKey', + Enable = 'enable', + Disable = 'disable', + MuteAll = 'muteAll', + UnmuteAll = 'unmuteAll', + MuteAlert = 'muteAlert', + UnmuteAlert = 'unmuteAlert', + Snooze = 'snooze', + BulkEdit = 'bulkEdit', + BulkDelete = 'bulkDelete', + BulkEnable = 'bulkEnable', + BulkDisable = 'bulkDisable', + Unsnooze = 'unsnooze', + RunSoon = 'runSoon', + ScheduleBackfill = 'scheduleBackfill', + DeleteBackfill = 'deleteBackfill', +} diff --git a/x-pack/plugins/alerting/server/config.test.ts b/x-pack/plugins/alerting/server/config.test.ts index 4b84905a12a6e..0cb75cb6162ce 100644 --- a/x-pack/plugins/alerting/server/config.test.ts +++ b/x-pack/plugins/alerting/server/config.test.ts @@ -21,7 +21,6 @@ describe('config validation', () => { "interval": "5m", "removalDelay": "1h", }, - "maxEphemeralActionsPerAlert": 10, "rules": Object { "maxScheduledPerMinute": 32000, "minimumScheduleInterval": Object { diff --git a/x-pack/plugins/alerting/server/config.ts b/x-pack/plugins/alerting/server/config.ts index be7790cd81888..776576cce2993 100644 --- a/x-pack/plugins/alerting/server/config.ts +++ b/x-pack/plugins/alerting/server/config.ts @@ -60,7 +60,6 @@ const rulesSchema = schema.object({ }), }); -export const DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT = 10; export const configSchema = schema.object({ healthCheck: schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '60m' }), @@ -69,9 +68,7 @@ export const configSchema = schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }), removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }), }), - maxEphemeralActionsPerAlert: schema.number({ - defaultValue: DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT, - }), + maxEphemeralActionsPerAlert: schema.maybe(schema.number()), enableFrameworkAlerts: schema.boolean({ defaultValue: true }), cancelAlertsOnRuleTimeout: schema.boolean({ defaultValue: true }), rules: rulesSchema, diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index 2cb2c212a91ba..fc00d37e6ebc3 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -36,8 +36,7 @@ export type { export { DEFAULT_AAD_CONFIG } from './types'; export { RULE_SAVED_OBJECT_TYPE, API_KEY_PENDING_INVALIDATION_TYPE } from './saved_objects'; export { RuleNotifyWhen } from '../common'; -export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config'; -export type { PluginSetupContract, PluginStartContract } from './plugin'; +export type { AlertingServerSetup, AlertingServerStart } from './plugin'; export type { FindResult, BulkEditOperation, BulkOperationError } from './rules_client'; export type { Rule } from './application/rule/types'; export type { PublicAlert as Alert } from './alert'; @@ -45,12 +44,13 @@ export { parseDuration, isRuleSnoozed } from './lib'; export { getEsErrorMessage } from './lib/errors'; export type { AlertingRulesConfig } from './config'; export { - ReadOperations, AlertingAuthorizationFilterType, AlertingAuthorization, + ReadOperations, WriteOperations, AlertingAuthorizationEntity, } from './authorization'; + export { DEFAULT_ALERTS_ILM_POLICY, DEFAULT_ALERTS_ILM_POLICY_NAME, @@ -84,9 +84,9 @@ export const config: PluginConfigDescriptor = { rules: { run: { alerts: { max: true } } }, }, deprecations: ({ renameFromRoot, deprecate }) => [ - deprecate('maxEphemeralActionsPerAlert', 'a future version', { + deprecate('maxEphemeralActionsPerAlert', '9.0.0', { level: 'warning', - message: `Configuring "xpack.alerting.maxEphemeralActionsPerAlert" is deprecated and will be removed in a future version. Remove this setting to increase action execution resiliency.`, + message: `The setting "xpack.alerting.maxEphemeralActionsPerAlert" is deprecated and currently ignored by the system. Please remove this setting.`, }), ], }; diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index 33cbccbaf8c0c..d885cf0721b4e 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -14,7 +14,7 @@ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { searchSourceCommonMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import { SharePluginStart } from '@kbn/share-plugin/server'; import { rulesClientMock } from './rules_client.mock'; -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { AlertingServerSetup, AlertingServerStart } from './plugin'; import { Alert, AlertFactoryDoneUtils } from './alert'; import { AlertInstanceContext, @@ -27,7 +27,7 @@ import { publicAlertsClientMock } from './alerts_client/alerts_client.mock'; export { rulesClientMock }; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = { registerType: jest.fn(), getSecurityHealth: jest.fn(), getConfig: jest.fn(), @@ -57,7 +57,7 @@ const createShareStartMock = () => { }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = { listTypes: jest.fn(), getType: jest.fn(), getAllTypes: jest.fn(), diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index 37175ac960412..2938daf8b1ec3 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertingPlugin, PluginSetupContract } from './plugin'; +import { AlertingPlugin, AlertingServerSetup } from './plugin'; import { createUsageCollectionSetupMock } from '@kbn/usage-collection-plugin/server/mocks'; import { coreMock, statusServiceMock } from '@kbn/core/server/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; @@ -170,7 +170,7 @@ describe('Alerting Plugin', () => { }); describe('registerType()', () => { - let setup: PluginSetupContract; + let setup: AlertingServerSetup; beforeEach(async () => { const context = coreMock.createPluginInitializerContext( generateAlertingConfig() @@ -209,7 +209,8 @@ describe('Alerting Plugin', () => { ...sampleRuleType, minimumLicenseRequired: 'basic', } as RuleType; - await setup.registerType(ruleType); + + setup.registerType(ruleType); expect(ruleType.ruleTaskTimeout).toBe('5m'); }); @@ -219,7 +220,7 @@ describe('Alerting Plugin', () => { minimumLicenseRequired: 'basic', ruleTaskTimeout: '20h', } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.ruleTaskTimeout).toBe('20h'); }); @@ -228,7 +229,7 @@ describe('Alerting Plugin', () => { ...sampleRuleType, minimumLicenseRequired: 'basic', } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.cancelAlertsOnRuleTimeout).toBe(true); }); @@ -238,13 +239,13 @@ describe('Alerting Plugin', () => { minimumLicenseRequired: 'basic', cancelAlertsOnRuleTimeout: false, } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.cancelAlertsOnRuleTimeout).toBe(false); }); }); describe('registerConnectorAdapter()', () => { - let setup: PluginSetupContract; + let setup: AlertingServerSetup; beforeEach(async () => { const context = coreMock.createPluginInitializerContext( @@ -314,9 +315,9 @@ describe('Alerting Plugin', () => { }); expect(encryptedSavedObjectsSetup.canEncrypt).toEqual(false); - expect(() => + await expect(() => startContract.getRulesClientWithRequest({} as KibanaRequest) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to create alerts client 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."` ); }); @@ -380,7 +381,8 @@ describe('Alerting Plugin', () => { }, getSavedObjectsClient: jest.fn(), } as unknown as KibanaRequest; - startContract.getRulesClientWithRequest(fakeRequest); + + await startContract.getRulesClientWithRequest(fakeRequest); }); }); @@ -443,7 +445,8 @@ describe('Alerting Plugin', () => { }, getSavedObjectsClient: jest.fn(), } as unknown as KibanaRequest; - startContract.getAlertingAuthorizationWithRequest(fakeRequest); + + await startContract.getAlertingAuthorizationWithRequest(fakeRequest); }); }); }); diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index bf1f02d3a4910..9d1a15305f7e3 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -61,7 +61,6 @@ import type { PluginSetup as UnifiedSearchServerPluginSetup } from '@kbn/unified import { PluginStart as DataPluginStart } from '@kbn/data-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; import { SharePluginStart } from '@kbn/share-plugin/server'; -import { ServerlessPluginSetup } from '@kbn/serverless/server'; import { RuleTypeRegistry } from './rule_type_registry'; import { TaskRunnerFactory } from './task_runner'; @@ -134,7 +133,7 @@ export const LEGACY_EVENT_LOG_ACTIONS = { resolvedInstance: 'resolved-instance', }; -export interface PluginSetupContract { +export interface AlertingServerSetup { registerConnectorAdapter< RuleActionParams extends ConnectorAdapterParams = ConnectorAdapterParams, ConnectorParams extends ConnectorAdapterParams = ConnectorAdapterParams @@ -169,19 +168,15 @@ export interface PluginSetupContract { getDataStreamAdapter: () => DataStreamAdapter; } -export interface PluginStartContract { +export interface AlertingServerStart { listTypes: RuleTypeRegistry['list']; - getAllTypes: RuleTypeRegistry['getAllTypes']; getType: RuleTypeRegistry['get']; getAlertIndicesAlias: GetAlertIndicesAlias; - - getRulesClientWithRequest(request: KibanaRequest): RulesClientApi; - + getRulesClientWithRequest(request: KibanaRequest): Promise; getAlertingAuthorizationWithRequest( request: KibanaRequest - ): PublicMethodsOf; - + ): Promise>; getFrameworkHealth: () => Promise; } @@ -198,7 +193,6 @@ export interface AlertingPluginsSetup { data: DataPluginSetup; features: FeaturesPluginSetup; unifiedSearch: UnifiedSearchServerPluginSetup; - serverless?: ServerlessPluginSetup; } export interface AlertingPluginsStart { @@ -213,7 +207,6 @@ export interface AlertingPluginsStart { data: DataPluginStart; dataViews: DataViewsPluginStart; share: SharePluginStart; - serverless?: ServerlessPluginSetup; } export class AlertingPlugin { @@ -239,6 +232,7 @@ export class AlertingPlugin { private pluginStop$: Subject; private dataStreamAdapter?: DataStreamAdapter; private backfillClient?: BackfillClient; + private readonly isServerless: boolean; private nodeRoles: PluginInitializerContext['node']['roles']; private readonly connectorAdapterRegistry = new ConnectorAdapterRegistry(); @@ -256,19 +250,20 @@ export class AlertingPlugin { this.kibanaVersion = initializerContext.env.packageInfo.version; this.inMemoryMetrics = new InMemoryMetrics(initializerContext.logger.get('in_memory_metrics')); this.pluginStop$ = new ReplaySubject(1); + this.isServerless = initializerContext.env.packageInfo.buildFlavor === 'serverless'; } public setup( core: CoreSetup, plugins: AlertingPluginsSetup - ): PluginSetupContract { + ): AlertingServerSetup { this.kibanaBaseUrl = core.http.basePath.publicBaseUrl; this.licenseState = new LicenseState(plugins.licensing.license$); this.security = plugins.security; const elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); - const useDataStreamForAlerts = !!plugins.serverless; + const useDataStreamForAlerts = this.isServerless; this.dataStreamAdapter = getDataStreamAdapter({ useDataStreamForAlerts }); core.capabilities.registerProvider(() => { @@ -282,7 +277,7 @@ export class AlertingPlugin { }; }); - plugins.features.registerKibanaFeature(getRulesSettingsFeature(!!plugins.serverless)); + plugins.features.registerKibanaFeature(getRulesSettingsFeature(this.isServerless)); plugins.features.registerKibanaFeature(maintenanceWindowFeature); @@ -330,6 +325,7 @@ export class AlertingPlugin { .getStartServices() .then(([{ elasticsearch }]) => elasticsearch.client.asInternalUser), elasticsearchAndSOAvailability$, + isServerless: this.isServerless, }); } } @@ -410,7 +406,8 @@ export class AlertingPlugin { getAlertIndicesAlias: createGetAlertIndicesAliasFn(this.ruleTypeRegistry!), encryptedSavedObjects: plugins.encryptedSavedObjects, config$: plugins.unifiedSearch.autocomplete.getInitializerContextConfig().create(), - isServerless: !!plugins.serverless, + isServerless: this.isServerless, + docLinks: core.docLinks, }); return { @@ -490,7 +487,7 @@ export class AlertingPlugin { }; } - public start(core: CoreStart, plugins: AlertingPluginsStart): PluginStartContract { + public start(core: CoreStart, plugins: AlertingPluginsStart): AlertingServerStart { const { isESOCanEncrypt, logger, @@ -517,7 +514,6 @@ export class AlertingPlugin { alertingAuthorizationClientFactory.initialize({ ruleTypeRegistry: ruleTypeRegistry!, - securityPluginSetup: security, securityPluginStart: plugins.security, async getSpace(request: KibanaRequest) { return plugins.spaces?.spacesService.getActiveSpace(request); @@ -561,7 +557,7 @@ export class AlertingPlugin { logger: this.logger, savedObjectsService: core.savedObjects, securityService: core.security, - isServerless: !!plugins.serverless, + isServerless: this.isServerless, }); maintenanceWindowClientFactory.initialize({ @@ -571,7 +567,7 @@ export class AlertingPlugin { uiSettings: core.uiSettings, }); - const getRulesClientWithRequest = (request: KibanaRequest) => { + const getRulesClientWithRequest = async (request: KibanaRequest) => { if (isESOCanEncrypt !== true) { throw new Error( `Unable to create alerts client 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.` @@ -580,7 +576,7 @@ export class AlertingPlugin { return rulesClientFactory!.create(request, core.savedObjects); }; - const getAlertingAuthorizationWithRequest = (request: KibanaRequest) => { + const getAlertingAuthorizationWithRequest = async (request: KibanaRequest) => { return alertingAuthorizationClientFactory!.create(request); }; @@ -614,28 +610,29 @@ export class AlertingPlugin { logger, }), maxAlerts: this.config.rules.run.alerts.max, - maxEphemeralActionsPerRule: this.config.maxEphemeralActionsPerAlert, ruleTypeRegistry: this.ruleTypeRegistry!, rulesSettingsService: new RulesSettingsService({ cacheInterval: this.config.rulesSettings.cacheInterval, getRulesSettingsClientWithRequest, - isServerless: !!plugins.serverless, + isServerless: this.isServerless, logger, }), savedObjects: core.savedObjects, share: plugins.share, spaceIdToNamespace, - supportsEphemeralTasks: plugins.taskManager.supportsEphemeralTasks(), uiSettings: core.uiSettings, usageCounter: this.usageCounter, + isServerless: this.isServerless, }); this.eventLogService!.registerSavedObjectProvider(RULE_SAVED_OBJECT_TYPE, (request) => { - const client = getRulesClientWithRequest(request); - return (objects?: SavedObjectsBulkGetObject[]) => - objects + return async (objects?: SavedObjectsBulkGetObject[]) => { + const client = await getRulesClientWithRequest(request); + + return objects ? Promise.all(objects.map(async (objectItem) => await client.get({ id: objectItem.id }))) : Promise.resolve([]); + }; }); this.eventLogService!.isEsContextReady() diff --git a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts index b2f25d349ec7f..a24ea147d4113 100644 --- a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts @@ -59,7 +59,7 @@ export function mockHandlerArguments( alerting: { listTypes, getRulesClient() { - return rulesClient || rulesClientMock.create(); + return Promise.resolve(rulesClient || rulesClientMock.create()); }, getRulesSettingsClient() { return rulesSettingsClient || rulesSettingsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts index 6c343ac125188..66d90671ac1bd 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts @@ -29,7 +29,8 @@ export const deleteBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: DeleteBackfillRequestParamsV1 = req.params; await rulesClient.deleteBackfill(params.id); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts index fea2925c0983b..be1ff25ef5932 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts @@ -34,7 +34,8 @@ export const findBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query: FindBackfillRequestQueryV1 = req.query; const result = await rulesClient.findBackfill(transformRequestV1(query)); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts index bfb178d875c8b..5758bb6ba805f 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts @@ -31,7 +31,8 @@ export const getBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: GetBackfillRequestParamsV1 = req.params; const result = await rulesClient.getBackfill(params.id); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts index 466c69b2b6aa5..77eb5c9355cfb 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts @@ -29,7 +29,8 @@ export const scheduleBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: ScheduleBackfillRequestBodyV1 = req.body; const result = await rulesClient.scheduleBackfill(transformRequestV1(body)); diff --git a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts index f726073ed0844..83773ab8531b7 100644 --- a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts @@ -25,7 +25,7 @@ jest.mock('../../../../lib/license_api_access', () => ({ const alerting = alertsMock.createStart(); const currentDate = new Date().toISOString(); -const ruleTypes = [ +const ruleTypes: RegistryAlertTypeWithAuth[] = [ { id: '1', name: 'name', @@ -48,12 +48,11 @@ const ruleTypes = [ category: 'test', producer: 'test', enabledInLicense: true, - minimumScheduleInterval: '1m', defaultScheduleInterval: '10m', hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], - } as RegistryAlertTypeWithAuth, + }, ]; beforeEach(() => { @@ -76,7 +75,7 @@ beforeEach(() => { describe('healthRoute', () => { it('registers the route', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -89,7 +88,7 @@ describe('healthRoute', () => { }); it('queries the usage api', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -113,7 +112,7 @@ describe('healthRoute', () => { }); it('throws error when user does not have any access to any rule types', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set()); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -139,7 +138,7 @@ describe('healthRoute', () => { }); it('evaluates whether Encrypted Saved Objects is missing encryption key', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -180,7 +179,7 @@ describe('healthRoute', () => { }); test('when ES security status cannot be determined from license state, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -222,7 +221,7 @@ describe('healthRoute', () => { }); test('when ES security is disabled, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -264,7 +263,7 @@ describe('healthRoute', () => { }); test('when ES security is enabled but user cannot generate api keys, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -306,7 +305,7 @@ describe('healthRoute', () => { }); test('when ES security is enabled and user can generate api keys, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); diff --git a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts index 34ef56a51daaa..4daf510b6a64f 100644 --- a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts +++ b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts @@ -48,8 +48,9 @@ export const healthRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { try { const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); // Verify that user has access to at least one rule type - const ruleTypes = Array.from(await alertingContext.getRulesClient().listRuleTypes()); + const ruleTypes = Array.from(await rulesClient.listRuleTypes()); if (ruleTypes.length > 0) { const alertingFrameworkHealth = await alertingContext.getFrameworkHealth(); diff --git a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts index 5da2189c1d43d..7406d07c3fa24 100644 --- a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts +++ b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts @@ -69,7 +69,8 @@ export const getActionErrorLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const withAuth = req.query.with_auth; const rewrittenReq = rewriteReq({ id, ...req.query }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts index 795b473dc8c66..48ea073369d2b 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts @@ -46,7 +46,8 @@ export const getGlobalExecutionKPIRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); return res.ok({ body: await rulesClient.getGlobalExecutionKpiWithAuth(rewriteReq(req.query)), }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts index 9c9e09e81bd45..13ea133e21a82 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts @@ -71,7 +71,8 @@ export const getGlobalExecutionLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); return res.ok({ body: await rulesClient.getGlobalExecutionLogWithAuth(rewriteReq(req.query)), }); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts index 7eaf5d4645ecb..937db706199e2 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts @@ -75,7 +75,8 @@ export const getRuleAlertSummaryRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const summary = await rulesClient.getAlertSummary(rewriteReq({ id, ...req.query })); return res.ok({ body: rewriteBodyRes(summary) }); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts index af15520d3c32f..302ac0293a444 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts @@ -48,7 +48,8 @@ export const getRuleExecutionKPIRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; return res.ok({ body: await rulesClient.getRuleExecutionKPI(rewriteReq({ id, ...req.query })), diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts index 619bc82bd6378..4eccefd171f0e 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts @@ -73,7 +73,8 @@ export const getRuleExecutionLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; return res.ok({ body: await rulesClient.getExecutionLogForRule(rewriteReq({ id, ...req.query })), diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.ts index 7530f1d4964cd..1a2b17b8f6747 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_state.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.ts @@ -47,7 +47,8 @@ export const getRuleStateRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const state = await rulesClient.getAlertState({ id }); return state ? res.ok({ body: rewriteBodyRes(state) }) : res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index 1a274692cefe4..d1fc9989be5e7 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from '@kbn/core/server'; +import { DocLinksServiceSetup, IRouter } from '@kbn/core/server'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import type { ConfigSchema } from '@kbn/unified-search-plugin/server/config'; @@ -81,6 +81,7 @@ export interface RouteOptions { usageCounter?: UsageCounter; config$?: Observable; isServerless?: boolean; + docLinks: DocLinksServiceSetup; } export function defineRoutes(opts: RouteOptions) { diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts index 52917ad5f3023..f3df843899f22 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -16,6 +16,7 @@ import { Rule, RuleSystemAction } from '../../../common/rule'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -32,6 +33,7 @@ beforeEach(() => { }); describe('createAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const createdAt = new Date(); const updatedAt = new Date(); @@ -104,6 +106,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -179,6 +182,7 @@ describe('createAlertRoute', () => { encryptedSavedObjects, usageCounter: mockUsageCounter, isServerless: true, + docLinks, }); const [config] = router.post.mock.calls[0]; @@ -204,6 +208,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -281,6 +286,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -359,6 +365,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -426,7 +433,7 @@ describe('createAlertRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -448,7 +455,7 @@ describe('createAlertRoute', () => { throw new Error('OMG'); }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -466,7 +473,7 @@ describe('createAlertRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -491,6 +498,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [, handler] = router.post.mock.calls[0]; rulesClient.create.mockResolvedValueOnce(createResult); @@ -511,6 +519,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -570,4 +579,39 @@ describe('createAlertRoute', () => { body: createResult, }); }); + + it('should be deprecated', () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + createAlertRoute({ + router, + licenseState, + encryptedSavedObjects, + usageCounter: mockUsageCounter, + docLinks, + }); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id?}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.ts b/x-pack/plugins/alerting/server/routes/legacy/create.ts index 333877b7df49e..8346ec37edf9c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.ts @@ -49,6 +49,7 @@ export const createAlertRoute = ({ licenseState, usageCounter, isServerless, + docLinks, }: RouteOptions) => { router.post( { @@ -65,8 +66,15 @@ export const createAlertRoute = ({ access: isServerless ? 'internal' : 'public', summary: 'Create an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id?}', + }, + }, }, }, handleDisabledApiKeysError( @@ -76,7 +84,9 @@ export const createAlertRoute = ({ if (!context.alerting) { return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } - const rulesClient = (await context.alerting).getRulesClient(); + + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const alert = req.body; const params = req.params; const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as RuleNotifyWhenType) : null; diff --git a/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts index 95a28904f4796..d8fd0effc50e4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts @@ -13,6 +13,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -29,11 +30,13 @@ beforeEach(() => { }); describe('deleteAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('deletes an alert with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [config, handler] = router.delete.mock.calls[0]; @@ -70,7 +73,7 @@ describe('deleteAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState, undefined, true); + deleteAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.delete.mock.calls[0]; @@ -82,7 +85,7 @@ describe('deleteAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [, handler] = router.delete.mock.calls[0]; @@ -108,7 +111,7 @@ describe('deleteAlertRoute', () => { throw new Error('OMG'); }); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [, handler] = router.delete.mock.calls[0]; @@ -132,7 +135,7 @@ describe('deleteAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - deleteAlertRoute(router, licenseState, mockUsageCounter); + deleteAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.delete.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -140,4 +143,30 @@ describe('deleteAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('delete', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + deleteAlertRoute(router, licenseState, docLinks); + + const [config] = router.delete.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "DELETE", + "newApiPath": "/api/alerting/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/delete.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.ts index 2b63de9e4ee73..738633c61f745 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/delete.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const deleteAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,15 @@ export const deleteAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Delete an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'DELETE', + newApiPath: '/api/alerting/rule/{id}', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +52,8 @@ export const deleteAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('delete', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; await rulesClient.delete({ id }); return res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts index 1c8ee110aca94..13fec185429ed 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts @@ -12,6 +12,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('disableAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('disables an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState); + disableAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('disableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState, undefined, true); + disableAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('disableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState); + disableAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('disableAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - disableAlertRoute(router, licenseState, mockUsageCounter); + disableAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -111,4 +114,30 @@ describe('disableAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('disable', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + disableAlertRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_disable", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.ts index 0c6f3cf062a0c..e69a176776e0c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const disableAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const disableAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Disable an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_disable', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const disableAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('disable', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.disableRule({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts index d2ed24cc3fa15..88df304ea07c0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts @@ -12,6 +12,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('enableAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('enables an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState); + enableAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('enableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState, undefined, true); + enableAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('enableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState); + enableAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('enableAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - enableAlertRoute(router, licenseState, mockUsageCounter); + enableAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -111,4 +114,30 @@ describe('enableAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('enable', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + enableAlertRoute(router, licenseState, docLinks, undefined, true); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_enable", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.ts index d52eaa784f670..289b4050e059b 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const enableAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const enableAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Enable an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_enable', + }, + }, }, }, handleDisabledApiKeysError( @@ -46,7 +55,8 @@ export const enableAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('enable', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.enableRule({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts index 0b8584be43da7..646f18fa072ea 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts @@ -15,6 +15,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -35,11 +36,13 @@ beforeEach(() => { }); describe('findAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('finds alerts with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -100,7 +103,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState, undefined, true); + findAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -112,7 +115,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -147,7 +150,7 @@ describe('findAlertRoute', () => { throw new Error('OMG'); }); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -173,7 +176,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { page: 1, @@ -195,7 +198,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { @@ -232,7 +235,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { page: 1, @@ -263,7 +266,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -407,4 +410,30 @@ describe('findAlertRoute', () => { body: omit(findResult, 'data[0].systemActions'), }); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findAlertRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rules/_find", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.ts b/x-pack/plugins/alerting/server/routes/legacy/find.ts index fa309ae51f2e4..de1e5f8c226a1 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { estypes } from '@elastic/elasticsearch'; import { KueryNode } from '@kbn/es-query'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; @@ -64,6 +65,7 @@ const querySchema = schema.object({ export const findAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -79,8 +81,15 @@ export const findAlertRoute = ( tags: ['oas-tag:alerting'], description: 'Gets a paginated set of alerts. Alert `params` are stored as a flattened field type and analyzed as keywords. As alerts change in Kibana, the results on each page of the response also change. Use the find API for traditional paginated results, but avoid using it to export large amounts of data.', - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rules/_find', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -95,7 +104,8 @@ export const findAlertRoute = ( ) as string[], usageCounter ); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query = req.query; const renameMap = { diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts index f27210c773878..ca8154fc7adae 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts @@ -14,6 +14,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { Rule, RuleSystemAction } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -29,6 +30,7 @@ beforeEach(() => { }); describe('getAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedAlert: Rule<{ bar: true; }> = { @@ -82,7 +84,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -111,7 +113,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState, undefined, true); + getAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -122,7 +124,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -149,7 +151,7 @@ describe('getAlertRoute', () => { throw new Error('OMG'); }); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -174,7 +176,7 @@ describe('getAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertRoute(router, licenseState, mockUsageCounter); + getAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; rulesClient.get.mockResolvedValueOnce(mockedAlert); @@ -190,7 +192,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -213,4 +215,29 @@ describe('getAlertRoute', () => { body: mockedAlert, }); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertRoute(router, licenseState, docLinks); + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.ts b/x-pack/plugins/alerting/server/routes/legacy/get.ts index e5eff52bf02d6..19fc0f7ff49e6 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const getAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,15 @@ export const getAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule/{id}', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +52,8 @@ export const getAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('get', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { systemActions, ...rule } = await rulesClient.get({ id, excludeFromPublicApi: true }); return res.ok({ diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts index 4ecc085c3bb40..cc3deaad9af99 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts @@ -14,6 +14,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { AlertSummary } from '../../types'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -29,6 +30,7 @@ beforeEach(() => { }); describe('getAlertInstanceSummaryRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const dateString = new Date().toISOString(); const mockedAlertInstanceSummary: AlertSummary = { id: '', @@ -55,7 +57,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -94,7 +96,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState, undefined, true); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -106,7 +108,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -136,7 +138,7 @@ describe('getAlertInstanceSummaryRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertInstanceSummaryRoute(router, licenseState, mockUsageCounter); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; rulesClient.getAlertSummary.mockResolvedValueOnce(mockedAlertInstanceSummary); @@ -148,4 +150,28 @@ describe('getAlertInstanceSummaryRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('instanceSummary', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertInstanceSummaryRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "type": "remove", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts index 58a75dd68dce7..0e50601a1fd4d 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -30,6 +31,7 @@ const rewriteBodyRes = ({ ruleTypeId, alerts, ...rest }: AlertSummary) => ({ export const getAlertInstanceSummaryRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -44,8 +46,13 @@ export const getAlertInstanceSummaryRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get an alert summary', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'remove', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -54,7 +61,8 @@ export const getAlertInstanceSummaryRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('instanceSummary', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { dateStart } = req.query; const summary = await rulesClient.getAlertSummary({ id, dateStart }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts index f8f1d4caeed9f..ca79291b23dbc 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts @@ -13,6 +13,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,6 +29,7 @@ beforeEach(() => { }); describe('getAlertStateRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedAlertState = { alertTypeState: { some: 'value', @@ -50,7 +52,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -87,7 +89,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState, undefined, true); + getAlertStateRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -99,7 +101,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -135,7 +137,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -175,7 +177,7 @@ describe('getAlertStateRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertStateRoute(router, licenseState, mockUsageCounter); + getAlertStateRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -183,4 +185,28 @@ describe('getAlertStateRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('state', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertStateRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "type": "remove", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts index e952ef8719667..f9db44c1e9a0c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const getAlertStateRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,13 @@ export const getAlertStateRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get the state of an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'remove', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +50,8 @@ export const getAlertStateRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('state', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const state = await rulesClient.getAlertState({ id }); return state ? res.ok({ body: state }) : res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.test.ts b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts index 6c0b3ae6f67a4..fea24b831e97d 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts @@ -16,6 +16,7 @@ import { RecoveredActionGroup } from '../../types'; import { alertsMock } from '../../mocks'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RegistryAlertTypeWithAuth } from '../../authorization'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -80,13 +81,15 @@ beforeEach(() => { }); describe('healthRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('registers the route', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [config] = router.get.mock.calls[0]; @@ -95,12 +98,12 @@ describe('healthRoute', () => { }); it('should have internal access for serverless', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - healthRoute(router, licenseState, encryptedSavedObjects, undefined, true); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -109,12 +112,12 @@ describe('healthRoute', () => { }); it('throws error when user does not have any access to any rule types', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set()); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: false }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -135,12 +138,12 @@ describe('healthRoute', () => { }); it('evaluates whether Encrypted Saved Objects is missing encryption key', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: false }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -192,13 +195,13 @@ describe('healthRoute', () => { }); test('when ES security status cannot be determined from license state, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(null); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -250,13 +253,13 @@ describe('healthRoute', () => { }); test('when ES security is disabled, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(false); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -308,13 +311,13 @@ describe('healthRoute', () => { }); test('when ES security is enabled but user cannot generate api keys, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(true); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -366,13 +369,13 @@ describe('healthRoute', () => { }); test('when ES security is enabled and user can generate api keys, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(true); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -424,14 +427,14 @@ describe('healthRoute', () => { }); it('should track every call', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - healthRoute(router, licenseState, encryptedSavedObjects, mockUsageCounter); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -439,4 +442,32 @@ describe('healthRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('health', mockUsageCounter); }); + + it('should be deprecated', async () => { + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule/_health", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.ts b/x-pack/plugins/alerting/server/routes/legacy/health.ts index 8f67767941fd2..b463298837f4e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/health.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/health.ts @@ -7,6 +7,7 @@ import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -18,6 +19,7 @@ export function healthRoute( router: AlertingRouter, licenseState: ILicenseState, encryptedSavedObjects: EncryptedSavedObjectsPluginSetup, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) { @@ -29,8 +31,15 @@ export function healthRoute( access: isServerless ? 'internal' : 'public', summary: 'Get the alerting framework health', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule/_health', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -41,8 +50,9 @@ export function healthRoute( trackLegacyRouteUsage('health', usageCounter); try { const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); // Verify that user has access to at least one rule type - const ruleTypes = Array.from(await alertingContext.getRulesClient().listRuleTypes()); + const ruleTypes = Array.from(await rulesClient.listRuleTypes()); if (ruleTypes.length > 0) { const alertingFrameworkHealth = await alertingContext.getFrameworkHealth(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/index.ts b/x-pack/plugins/alerting/server/routes/legacy/index.ts index 99220106d5ac1..e9551d938e6c1 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/index.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/index.ts @@ -24,22 +24,23 @@ import { healthRoute } from './health'; import { RouteOptions } from '..'; export function defineLegacyRoutes(opts: RouteOptions) { - const { router, licenseState, encryptedSavedObjects, usageCounter, isServerless } = opts; + const { router, licenseState, encryptedSavedObjects, usageCounter, isServerless, docLinks } = + opts; createAlertRoute(opts); - deleteAlertRoute(router, licenseState, usageCounter, isServerless); - findAlertRoute(router, licenseState, usageCounter, isServerless); - getAlertRoute(router, licenseState, usageCounter, isServerless); - getAlertStateRoute(router, licenseState, usageCounter, isServerless); - getAlertInstanceSummaryRoute(router, licenseState, usageCounter, isServerless); - listAlertTypesRoute(router, licenseState, usageCounter, isServerless); - updateAlertRoute(router, licenseState, usageCounter, isServerless); - enableAlertRoute(router, licenseState, usageCounter, isServerless); - disableAlertRoute(router, licenseState, usageCounter, isServerless); - updateApiKeyRoute(router, licenseState, usageCounter, isServerless); - muteAllAlertRoute(router, licenseState, usageCounter, isServerless); - unmuteAllAlertRoute(router, licenseState, usageCounter, isServerless); - muteAlertInstanceRoute(router, licenseState, usageCounter, isServerless); - unmuteAlertInstanceRoute(router, licenseState, usageCounter, isServerless); - healthRoute(router, licenseState, encryptedSavedObjects, usageCounter, isServerless); + deleteAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + findAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertStateRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, usageCounter, isServerless); + listAlertTypesRoute(router, licenseState, docLinks, usageCounter, isServerless); + updateAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + enableAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + disableAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + updateApiKeyRoute(router, licenseState, docLinks, usageCounter, isServerless); + muteAllAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + unmuteAllAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + muteAlertInstanceRoute(router, licenseState, docLinks, usageCounter, isServerless); + unmuteAlertInstanceRoute(router, licenseState, docLinks, usageCounter, isServerless); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, usageCounter, isServerless); } diff --git a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts index 80298f7fd288e..27e9d7ce44865 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts @@ -15,6 +15,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { RecoveredActionGroup } from '../../../common'; import { RegistryAlertTypeWithAuth } from '../../authorization'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -31,18 +32,19 @@ beforeEach(() => { }); describe('listAlertTypesRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); it('lists alert types with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/list_alert_types"`); expect(config.options?.access).toBe('public'); - const listTypes = [ + const listTypes: RegistryAlertTypeWithAuth[] = [ { id: '1', name: 'name', @@ -67,9 +69,10 @@ describe('listAlertTypesRoute', () => { hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], - } as RegistryAlertTypeWithAuth, + }, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']); @@ -119,7 +122,7 @@ describe('listAlertTypesRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState, undefined, true); + listAlertTypesRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -131,7 +134,7 @@ describe('listAlertTypesRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -165,7 +168,7 @@ describe('listAlertTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -188,7 +191,7 @@ describe('listAlertTypesRoute', () => { throw new Error('OMG'); }); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -222,7 +225,7 @@ describe('listAlertTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -243,9 +246,9 @@ describe('listAlertTypesRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set([])); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); - listAlertTypesRoute(router, licenseState, mockUsageCounter); + listAlertTypesRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -255,4 +258,30 @@ describe('listAlertTypesRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('listAlertTypes', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + listAlertTypesRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule_types", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts index 35d6a7efeeee3..f4f2bc7936b3d 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts @@ -5,6 +5,7 @@ * 2.0. */ import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -14,6 +15,7 @@ import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; export const listAlertTypesRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -25,8 +27,15 @@ export const listAlertTypesRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get the alert types', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule_types', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -36,8 +45,10 @@ export const listAlertTypesRoute = ( } trackLegacyRouteUsage('listAlertTypes', usageCounter); const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); + return res.ok({ - body: Array.from(await alertingContext.getRulesClient().listRuleTypes()), + body: Array.from(await rulesClient.listRuleTypes()), }); }) ); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts index 9a9ea27ba6751..d80cf415283d0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('muteAllAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('mute an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState); + muteAllAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('muteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState, undefined, true); + muteAllAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('muteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState); + muteAllAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('muteAllAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - muteAllAlertRoute(router, licenseState, mockUsageCounter); + muteAllAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -111,4 +114,30 @@ describe('muteAllAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('muteAll', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAllAlertRoute(router, licenseState, docLinks, undefined, true); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_mute_all", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts index 5c4fc1542ef5b..75c860167f21c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const muteAllAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const muteAllAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Mute all alert instances', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_mute_all', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const muteAllAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('muteAll', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.muteAll({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts index 7a142e4e94854..08e03a6d053ef 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('muteAlertInstanceRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('mutes an alert instance', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState); + muteAlertInstanceRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -73,7 +76,7 @@ describe('muteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState, undefined, true); + muteAlertInstanceRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -87,7 +90,7 @@ describe('muteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState); + muteAlertInstanceRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -111,7 +114,7 @@ describe('muteAlertInstanceRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - muteAlertInstanceRoute(router, licenseState, mockUsageCounter); + muteAlertInstanceRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -119,4 +122,30 @@ describe('muteAlertInstanceRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('muteInstance', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAlertInstanceRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts index ab0b52d41de29..23225c387ccaa 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -24,6 +25,7 @@ const paramSchema = schema.object({ export const muteAlertInstanceRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -37,8 +39,15 @@ export const muteAlertInstanceRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Mute an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -49,7 +58,8 @@ export const muteAlertInstanceRoute = ( trackLegacyRouteUsage('muteInstance', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const renameMap = { alert_id: 'alertId', diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts index 6a88335ec98ae..5ae337e6a3f51 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('unmuteAllAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('unmutes an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState); + unmuteAllAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('unmuteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState, undefined, true); + unmuteAllAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('unmuteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState); + unmuteAllAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('unmuteAllAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - unmuteAllAlertRoute(router, licenseState, mockUsageCounter); + unmuteAllAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -111,4 +114,30 @@ describe('unmuteAllAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('unmuteAll', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAllAlertRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_unmute_all", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts index 0681e7d2cf01e..2684ea60d7336 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const unmuteAllAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const unmuteAllAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Unmute all alert instances', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_unmute_all', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const unmuteAllAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('unmuteAll', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.unmuteAll({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts index b04f376c38ca1..b6fba61aaff8a 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('unmuteAlertInstanceRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('unmutes an alert instance', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState); + unmuteAlertInstanceRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -73,7 +76,7 @@ describe('unmuteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState, undefined, true); + unmuteAlertInstanceRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -87,7 +90,7 @@ describe('unmuteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState); + unmuteAlertInstanceRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -111,7 +114,7 @@ describe('unmuteAlertInstanceRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - unmuteAlertInstanceRoute(router, licenseState, mockUsageCounter); + unmuteAlertInstanceRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -119,4 +122,30 @@ describe('unmuteAlertInstanceRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('unmuteInstance', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAlertInstanceRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts index 1101a2b5092e7..e6122a92509b0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const unmuteAlertInstanceRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const unmuteAlertInstanceRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Unmute an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -45,7 +54,8 @@ export const unmuteAlertInstanceRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('unmuteInstance', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { alertId, alertInstanceId } = req.params; try { await rulesClient.unmuteInstance({ alertId, alertInstanceId }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts index fc4a814c26a27..7aaee90b805c5 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts @@ -15,6 +15,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { RuleNotifyWhen, SanitizedRule, RuleSystemAction } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -30,6 +31,7 @@ beforeEach(() => { }); describe('updateAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedResponse = { id: '1', alertTypeId: '1', @@ -66,7 +68,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [config, handler] = router.put.mock.calls[0]; @@ -145,7 +147,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState, undefined, true); + updateAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.put.mock.calls[0]; @@ -157,7 +159,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -204,7 +206,7 @@ describe('updateAlertRoute', () => { throw new Error('OMG'); }); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -247,7 +249,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -269,7 +271,7 @@ describe('updateAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - updateAlertRoute(router, licenseState, mockUsageCounter); + updateAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.put.mock.calls[0]; rulesClient.update.mockResolvedValueOnce(mockedResponse as unknown as SanitizedRule); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ @@ -283,7 +285,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [config, handler] = router.put.mock.calls[0]; @@ -359,4 +361,30 @@ describe('updateAlertRoute', () => { expect(res.ok).toHaveBeenCalled(); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateAlertRoute(router, licenseState, docLinks); + + const [config] = router.put.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "PUT", + "newApiPath": "/api/alerting/rule/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.ts b/x-pack/plugins/alerting/server/routes/legacy/update.ts index 01adeb5c634dc..3e3d3b5a480f0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -47,6 +48,7 @@ const bodySchema = schema.object({ export const updateAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -61,8 +63,15 @@ export const updateAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Update an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'PUT', + newApiPath: '/api/alerting/rule/rule/{id}', + }, + }, }, }, handleDisabledApiKeysError( @@ -72,7 +81,8 @@ export const updateAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('update', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { name, actions, params, schedule, tags, throttle, notifyWhen } = req.body; try { diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts index cd5b6639ad004..cb2817af2ed58 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('updateApiKeyRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('updates api key for an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState); + updateApiKeyRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('updateApiKeyRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState, undefined, true); + updateApiKeyRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('updateApiKeyRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState); + updateApiKeyRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -105,7 +108,7 @@ describe('updateApiKeyRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - updateApiKeyRoute(router, licenseState, mockUsageCounter); + updateApiKeyRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -113,4 +116,29 @@ describe('updateApiKeyRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('updateApiKey', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateApiKeyRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_update_api_key", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts index 30c51d3cdcf5c..603a321768573 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const updateApiKeyRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const updateApiKeyRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Update the API key for an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_update_api_key', + }, + }, }, }, handleDisabledApiKeysError( @@ -46,7 +55,8 @@ export const updateApiKeyRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('updateApiKey', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.updateRuleApiKey({ id }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts index 77221de2d714b..74a94cbba80a1 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts @@ -145,6 +145,7 @@ describe('aggregateRulesRoute', () => { { body: { default_search_operator: 'AND', + rule_type_ids: ['foo'], }, }, ['ok'] @@ -237,6 +238,9 @@ describe('aggregateRulesRoute', () => { }, "options": Object { "defaultSearchOperator": "AND", + "ruleTypeIds": Array [ + "foo", + ], }, }, ] diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts index 9b595858793f8..05c5fc2167e11 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts @@ -37,7 +37,8 @@ export const aggregateRulesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: AggregateRulesRequestBodyV1 = req.body; const options = transformAggregateQueryRequestV1({ ...body, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts index baa6b9bb46f9c..ae13f08d0afa5 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts @@ -13,13 +13,15 @@ export const transformAggregateQueryRequest: RewriteRequestCase ({ defaultSearchOperator, ...(hasReference ? { hasReference } : {}), ...(searchFields ? { searchFields } : {}), ...(search ? { search } : {}), - ...(filterConsumers ? { filterConsumers } : {}), + ...(ruleTypeIds ? { ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), ...(filter ? { filter } : {}), }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts index 8bd6f7fc19916..8548464d44812 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts @@ -36,7 +36,8 @@ export const bulkDeleteRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkDeleteRulesRequestBodyV1 = req.body; const { filter, ids } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts index 724eda3ae7b87..315904efa40a7 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts @@ -37,7 +37,8 @@ export const bulkDisableRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkDisableRulesRequestBodyV1 = req.body; const { filter, ids, untrack } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts index 4c853beeec250..f516b63031aad 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts @@ -41,7 +41,8 @@ const buildBulkEditRulesRoute = ({ licenseState, path, router }: BuildBulkEditRu handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const bulkEditData: BulkEditRulesRequestBodyV1 = req.body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts index da97949fd0feb..71932cb6d78bb 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts @@ -35,7 +35,8 @@ export const bulkEnableRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkEnableRulesRequestBodyV1 = req.body; try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts index 622218705b510..a43cc48d95631 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts @@ -28,7 +28,8 @@ export const bulkUntrackAlertsRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkUntrackRequestBodyV1 = req.body; try { await rulesClient.bulkUntrackAlerts({ diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts index 3486005d3b588..ebaab0cb98402 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts @@ -45,7 +45,7 @@ describe('bulkUntrackAlertsByQueryRoute', () => { }, }, ], - feature_ids: ['o11y'], + rule_type_ids: ['o11y'], }; const [context, req, res] = mockHandlerArguments( @@ -62,7 +62,7 @@ describe('bulkUntrackAlertsByQueryRoute', () => { expect(rulesClient.bulkUntrackAlerts.mock.calls[0]).toEqual([ { query: requestBody.query, - featureIds: requestBody.feature_ids, + ruleTypeIds: requestBody.rule_type_ids, isUsingQuery: true, }, ]); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts index 5cebdb8c6e7f4..735cd75b7f4a9 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts @@ -29,7 +29,8 @@ export const bulkUntrackAlertsByQueryRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkUntrackByQueryRequestBodyV1 = req.body; try { await rulesClient.bulkUntrackAlerts({ diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts index 87c58c48c4c6d..dd346f8cc818e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts @@ -9,8 +9,8 @@ import type { BulkUntrackByQueryRequestBodyV1 } from '../../../../../../../commo export const transformBulkUntrackAlertsByQueryBody = ({ query, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, }: BulkUntrackByQueryRequestBodyV1) => ({ query, - featureIds, + ruleTypeIds, }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts index ea6460dfb9463..0aa23886a9b4a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts @@ -33,7 +33,8 @@ export const cloneRuleRoute = ( handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: CloneRuleRequestParamsV1 = req.params; try { // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts index cab3956161613..f778b09854abd 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts @@ -18,6 +18,7 @@ import { RuleAction, RuleSystemAction, SanitizedRule } from '../../../../types'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; import { actionsClientMock } from '@kbn/actions-plugin/server/mocks'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -30,6 +31,7 @@ beforeEach(() => { }); describe('createRuleRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const createdAt = new Date(); const updatedAt = new Date(); const action: RuleAction = { @@ -151,6 +153,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -264,6 +267,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -381,6 +385,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -499,6 +504,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -606,7 +612,7 @@ describe('createRuleRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -628,7 +634,7 @@ describe('createRuleRoute', () => { throw new Error('OMG'); }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -646,7 +652,7 @@ describe('createRuleRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -677,6 +683,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; @@ -759,6 +766,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; @@ -815,6 +823,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts index 45341fb48e9bd..26775ad0f98d4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts @@ -62,7 +62,8 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts index 0452de7f7becd..e1e09403b309a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts @@ -48,7 +48,8 @@ export const deleteRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: DeleteRuleRequestParamsV1 = req.params; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts index cae82e80be869..e364bc130121d 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts @@ -51,7 +51,7 @@ export const disableRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const { id }: DisableRuleRequestParamsV1 = req.params; const body: DisableRuleRequestBodyV1 = req.body || {}; const { untrack = false } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts index 4843ed932374d..e5f0983bf844b 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts @@ -48,7 +48,7 @@ export const enableRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const params: EnableRuleRequestParamsV1 = req.params; try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts index 46ff2e8e96e12..53b330a8a2044 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts @@ -7,6 +7,8 @@ import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../../lib/license_state.mock'; import { findInternalRulesRoute } from './find_internal_rules_route'; +import { mockHandlerArguments } from '../../../_mock_handler_arguments'; +import { rulesClientMock } from '../../../../rules_client.mock'; jest.mock('../../../../lib/license_api_access', () => ({ verifyApiAccess: jest.fn(), @@ -20,6 +22,8 @@ beforeEach(() => { jest.resetAllMocks(); }); +const rulesClient = rulesClientMock.create(); + describe('findInternalRulesRoute', () => { it('registers the route without public access', async () => { const licenseState = licenseStateMock.create(); @@ -33,4 +37,78 @@ describe('findInternalRulesRoute', () => { expect.any(Function) ); }); + + it('finds rules with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findInternalRulesRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + body: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + rule_type_ids: ['foo'], + consumers: ['bar'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": false, + "includeSnoozeData": true, + "options": Object { + "consumers": Array [ + "bar", + ], + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + "ruleTypeIds": Array [ + "foo", + ], + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts index 8ff8ce59192cf..0117d86468f2a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts @@ -8,10 +8,10 @@ import { IRouter } from '@kbn/core/server'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import type { - FindRulesRequestQueryV1, + FindRulesInternalRequestBodyV1, FindRulesResponseV1, } from '../../../../../common/routes/rule/apis/find'; -import { findRulesRequestQuerySchemaV1 } from '../../../../../common/routes/rule/apis/find'; +import { findRulesInternalRequestBodySchemaV1 } from '../../../../../common/routes/rule/apis/find'; import { RuleParamsV1 } from '../../../../../common/routes/rule/response'; import { ILicenseState } from '../../../../lib'; import { @@ -20,7 +20,7 @@ import { } from '../../../../types'; import { verifyAccessAndContext } from '../../../lib'; import { trackLegacyTerminology } from '../../../lib/track_legacy_terminology'; -import { transformFindRulesBodyV1, transformFindRulesResponseV1 } from './transforms'; +import { transformFindRulesInternalBodyV1, transformFindRulesResponseV1 } from './transforms'; export const findInternalRulesRoute = ( router: IRouter, @@ -32,14 +32,14 @@ export const findInternalRulesRoute = ( path: INTERNAL_ALERTING_API_FIND_RULES_PATH, options: { access: 'internal' }, validate: { - body: findRulesRequestQuerySchemaV1, + body: findRulesInternalRequestBodySchemaV1, }, }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); - const body: FindRulesRequestQueryV1 = req.body; + const body: FindRulesInternalRequestBodyV1 = req.body; trackLegacyTerminology( [req.body.search, req.body.search_fields, req.body.sort_field].filter( @@ -48,7 +48,7 @@ export const findInternalRulesRoute = ( usageCounter ); - const options = transformFindRulesBodyV1({ + const options = transformFindRulesInternalBodyV1({ ...body, has_reference: body.has_reference || undefined, search_fields: searchFieldsAsArray(body.search_fields), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts index 0e1f07a5ce543..27769cf237389 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts @@ -42,6 +42,7 @@ describe('findRulesRoute', () => { expect.any(Function) ); }); + it('finds rules with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); @@ -446,4 +447,138 @@ describe('findRulesRoute', () => { incrementBy: 1, }); }); + + it('should not support rule_type_ids', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + rule_type_ids: ['foo'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": true, + "includeSnoozeData": true, + "options": Object { + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); + + it('should not support consumers', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + consumers: ['foo'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": true, + "includeSnoozeData": true, + "options": Object { + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts index 90afde8f20813..37ea13c7983e6 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts @@ -52,7 +52,7 @@ export const findRulesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const query: FindRulesRequestQueryV1 = req.query; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts index 044a845f3f8f3..222215ffb9a31 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts @@ -8,5 +8,8 @@ export { transformFindRulesBody } from './transform_find_rules_body/latest'; export { transformFindRulesResponse } from './transform_find_rules_response/latest'; -export { transformFindRulesBody as transformFindRulesBodyV1 } from './transform_find_rules_body/v1'; +export { + transformFindRulesBody as transformFindRulesBodyV1, + transformFindRulesInternalBody as transformFindRulesInternalBodyV1, +} from './transform_find_rules_body/v1'; export { transformFindRulesResponse as transformFindRulesResponseV1 } from './transform_find_rules_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts index a2f9d3c99b00d..3248c8f45360a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts @@ -5,7 +5,10 @@ * 2.0. */ -import type { FindRulesRequestQueryV1 } from '../../../../../../../common/routes/rule/apis/find'; +import type { + FindRulesInternalRequestBodyV1, + FindRulesRequestQueryV1, +} from '../../../../../../../common/routes/rule/apis/find'; import { FindRulesOptions } from '../../../../../../application/rule/methods/find'; export const transformFindRulesBody = (params: FindRulesRequestQueryV1): FindRulesOptions => { @@ -29,7 +32,42 @@ export const transformFindRulesBody = (params: FindRulesRequestQueryV1): FindRul ...(filter ? { filter } : {}), ...(defaultSearchOperator ? { defaultSearchOperator } : {}), ...(perPage ? { perPage } : {}), - ...(filterConsumers ? { filterConsumers } : {}), + ...(sortField ? { sortField } : {}), + ...(sortOrder ? { sortOrder } : {}), + ...(hasReference ? { hasReference } : {}), + ...(searchFields + ? { searchFields: Array.isArray(searchFields) ? searchFields : [searchFields] } + : {}), + ...(filterConsumers ? { consumers: filterConsumers } : {}), + }; +}; + +export const transformFindRulesInternalBody = ( + params: FindRulesInternalRequestBodyV1 +): FindRulesOptions => { + const { + per_page: perPage, + page, + search, + default_search_operator: defaultSearchOperator, + search_fields: searchFields, + sort_field: sortField, + sort_order: sortOrder, + has_reference: hasReference, + fields, + filter, + rule_type_ids: ruleTypeIds, + consumers, + } = params; + return { + ...(page ? { page } : {}), + ...(search ? { search } : {}), + ...(fields ? { fields } : {}), + ...(filter ? { filter } : {}), + ...(defaultSearchOperator ? { defaultSearchOperator } : {}), + ...(perPage ? { perPage } : {}), + ...(ruleTypeIds ? { ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), ...(sortField ? { sortField } : {}), ...(sortOrder ? { sortOrder } : {}), ...(hasReference ? { hasReference } : {}), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts index 0c19d0c9c4f70..46ccc00e33626 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts @@ -64,7 +64,8 @@ const buildGetRuleRoute = ({ }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: GetRuleRequestParamsV1 = req.params; // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts index e130679a78437..b91c0841df911 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts @@ -24,7 +24,8 @@ export const getScheduleFrequencyRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const scheduleFrequencyResult = await rulesClient.getScheduleFrequency(); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts index e6293a589743b..d32df997eb2c3 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts @@ -97,7 +97,7 @@ describe('ruleTypesRoute', () => { has_fields_for_a_a_d: false, }, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']); @@ -183,7 +183,7 @@ describe('ruleTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -240,7 +240,7 @@ describe('ruleTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts index da9c62ab5f3f2..a49820704d74a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts @@ -42,7 +42,7 @@ export const ruleTypesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const ruleTypes = await rulesClient.listRuleTypes(); const responseBody: TypesRulesResponseBodyV1 = transformRuleTypesResponseV1(ruleTypes); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts index 54a5874331c86..e331fd9133332 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts @@ -10,9 +10,9 @@ import { RegistryAlertTypeWithAuth } from '../../../../../../authorization'; import type { TypesRulesResponseBodyV1 } from '../../../../../../../common/routes/rule/apis/list_types'; export const transformRuleTypesResponse = ( - ruleTypes: Set + ruleTypes: RegistryAlertTypeWithAuth[] ): TypesRulesResponseBodyV1 => { - return Array.from(ruleTypes).map((ruleType: RegistryAlertTypeWithAuth) => { + return ruleTypes.map((ruleType: RegistryAlertTypeWithAuth) => { return { ...(ruleType.actionGroups ? { action_groups: ruleType.actionGroups } : {}), ...(ruleType.actionVariables ? { action_variables: ruleType.actionVariables } : {}), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts index 5ce924b445ca7..f9b7fa8bfbf0e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts @@ -48,7 +48,8 @@ export const muteAlertRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: MuteAlertRequestParamsV1 = req.params; try { await rulesClient.muteInstance(transformRequestParamsToApplicationV1(params)); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts index e9aa0e42a046f..46f108cb3a94e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts @@ -51,7 +51,8 @@ export const muteAllRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: MuteAllRuleRequestParamsV1 = req.params; trackDeprecatedRouteUsage('muteAll', usageCounter); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts index f67485279edc5..ad0e846d452e5 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts @@ -34,7 +34,8 @@ export const resolveRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: ResolveRuleRequestParamsV1 = req.params; const { id } = params; // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts index 1de46fd784905..3e0e22070d672 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts @@ -33,7 +33,8 @@ export const snoozeRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: SnoozeRuleRequestParamsV1 = req.params; const body = transformSnoozeBodyV1(req.body); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts b/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts index c66bf0d61009a..05e4433f5e53d 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts @@ -29,7 +29,8 @@ export const getRuleTagsRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query: RuleTagsRequestQueryV1 = req.query; const options = transformRuleTagsQueryRequestV1(query); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts index 63560e354dc1b..34108b937cc43 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts @@ -49,7 +49,7 @@ export const unmuteAlertRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const params: UnmuteAlertRequestParamsV1 = req.params; try { await rulesClient.unmuteInstance(transformRequestParamsToApplicationV1(params)); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts index 8409128da6241..bf9d1660d0def 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts @@ -48,7 +48,8 @@ export const unmuteAllRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: UnmuteAllRuleRequestParamsV1 = req.params; try { await rulesClient.unmuteAll(params); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts index 69e4c91eeaf35..e5f476cbb2038 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts @@ -33,7 +33,8 @@ export const unsnoozeRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: UnsnoozeRuleRequestParamsV1 = req.params; const body = transformUnsnoozeBodyV1(req.body); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts index 5c925b05bace3..8fee470cb3bd7 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts @@ -64,7 +64,8 @@ export const updateRuleRoute = ( handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts index 7ba8589412357..4f16d873dfaa8 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts @@ -51,7 +51,7 @@ export const updateRuleApiKeyRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const { id }: UpdateApiKeyParamsV1 = req.params; try { diff --git a/x-pack/plugins/alerting/server/routes/run_soon.ts b/x-pack/plugins/alerting/server/routes/run_soon.ts index 589724ab57b06..1b7fa271c9587 100644 --- a/x-pack/plugins/alerting/server/routes/run_soon.ts +++ b/x-pack/plugins/alerting/server/routes/run_soon.ts @@ -31,7 +31,8 @@ export const runSoonRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const message = await rulesClient.runSoon(req.params); return message ? res.ok({ body: message }) : res.noContent(); }) diff --git a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts index f39615efa7e8d..25dc8add03abf 100644 --- a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts +++ b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts @@ -11,15 +11,9 @@ import { firstValueFrom, Observable } from 'rxjs'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { termsAggSuggestions } from '@kbn/unified-search-plugin/server/autocomplete/terms_agg'; import type { ConfigSchema } from '@kbn/unified-search-plugin/server/config'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { getKbnServerError, reportServerError } from '@kbn/kibana-utils-plugin/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - AlertConsumers, - ALERT_RULE_CONSUMER, - ALERT_RULE_TYPE_ID, - SPACE_IDS, -} from '@kbn/rule-data-utils'; +import { ALERT_RULE_CONSUMER, ALERT_RULE_TYPE_ID, SPACE_IDS } from '@kbn/rule-data-utils'; import { verifyAccessAndContext } from '../lib'; import { RuleAuditAction, ruleAuditEvent } from '../../rules_client/common/audit_events'; @@ -27,6 +21,7 @@ import { AlertingAuthorizationEntity, AlertingAuthorizationFilterOpts, AlertingAuthorizationFilterType, + AuthorizedRuleTypes, } from '../../authorization'; import { AlertingRequestHandlerContext } from '../../types'; import { GetAlertIndicesAlias, ILicenseState } from '../../lib'; @@ -45,20 +40,11 @@ export const AlertsSuggestionsSchema = { }), }; -const VALID_FEATURE_IDS = new Set([ - AlertConsumers.APM, - AlertConsumers.INFRASTRUCTURE, - AlertConsumers.LOGS, - AlertConsumers.SLO, - AlertConsumers.UPTIME, -]); - export function registerAlertsValueSuggestionsRoute( router: IRouter, licenseState: ILicenseState, config$: Observable, - getAlertIndicesAlias?: GetAlertIndicesAlias, - usageCounter?: UsageCounter + getAlertIndicesAlias?: GetAlertIndicesAlias ) { router.post( { @@ -73,19 +59,21 @@ export function registerAlertsValueSuggestionsRoute( const abortSignal = getRequestAbortedSignal(request.events.aborted$); const { savedObjects, elasticsearch } = await context.core; - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); let authorizationTuple; - let authorizedRuleType = []; + let authorizedRuleType: AuthorizedRuleTypes = new Map(); + try { const authorization = rulesClient.getAuthorization(); - authorizationTuple = await authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - alertingAuthorizationFilterOpts - ); - authorizedRuleType = await authorization.getAuthorizedRuleTypes( - AlertingAuthorizationEntity.Alert, - VALID_FEATURE_IDS - ); + authorizationTuple = await authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: alertingAuthorizationFilterOpts, + }); + + authorizedRuleType = await authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + }); } catch (error) { rulesClient.getAuditLogger()?.log( ruleAuditEvent({ @@ -93,8 +81,10 @@ export function registerAlertsValueSuggestionsRoute( error, }) ); + throw error; } + const spaceId = rulesClient.getSpaceId(); const { filter: authorizationFilter } = authorizationTuple; const filters = [ @@ -103,9 +93,10 @@ export function registerAlertsValueSuggestionsRoute( ] as estypes.QueryDslQueryContainer[]; const index = getAlertIndicesAlias!( - authorizedRuleType.map((art) => art.id), + Array.from(authorizedRuleType.keys()).map((id) => id), spaceId ).join(','); + try { const body = await termsAggSuggestions( config, diff --git a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts index 6ada2378b3096..420d6473988fa 100644 --- a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts +++ b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts @@ -59,15 +59,14 @@ export function registerRulesValueSuggestionsRoute( const abortSignal = getRequestAbortedSignal(request.events.aborted$); const { savedObjects, elasticsearch } = await context.core; - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); let authorizationTuple; try { - authorizationTuple = await rulesClient - .getAuthorization() - .getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await rulesClient.getAuthorization().getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { rulesClient.getAuditLogger()?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index e678228660e51..d9d7c1240922c 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -856,7 +856,7 @@ describe('Create Lifecycle', () => { test('should return empty when nothing is registered', () => { const registry = new RuleTypeRegistry(ruleTypeRegistryParams); const result = registry.list(); - expect(result).toMatchInlineSnapshot(`Set {}`); + expect(result).toMatchInlineSnapshot(`Map {}`); }); test('should return registered types', () => { @@ -888,8 +888,8 @@ describe('Create Lifecycle', () => { }); const result = registry.list(); expect(result).toMatchInlineSnapshot(` - Set { - Object { + Map { + "test" => Object { "actionGroups": Array [ Object { "id": "testActionGroup", diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 7562942f0262d..40d00acbef598 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -382,59 +382,40 @@ export class RuleTypeRegistry { >; } - public list(): Set { - const mapRuleTypes: Array<[string, UntypedNormalizedRuleType]> = Array.from(this.ruleTypes); - const tempRegistryRuleType = mapRuleTypes.map( - ([ - id, - { - name, - actionGroups, - recoveryActionGroup, - defaultActionGroupId, - actionVariables, - category, - producer, - minimumLicenseRequired, - isExportable, - ruleTaskTimeout, - defaultScheduleInterval, - doesSetRecoveryContext, - alerts, - fieldsForAAD, - validLegacyConsumers, - }, - ]) => { - // KEEP the type here to be safe if not the map is ignoring it for some reason - const ruleType: RegistryRuleType = { - id, - name, - actionGroups, - recoveryActionGroup, - defaultActionGroupId, - actionVariables, - category, - producer, - minimumLicenseRequired, - isExportable, - ruleTaskTimeout, - defaultScheduleInterval, - doesSetRecoveryContext, - enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType( - id, - name, - minimumLicenseRequired - ).isValid, - fieldsForAAD, - hasFieldsForAAD: Boolean(fieldsForAAD), - hasAlertsMappings: !!alerts, - validLegacyConsumers, - ...(alerts ? { alerts } : {}), - }; - return ruleType; - } - ); - return new Set(tempRegistryRuleType); + public list(): Map { + const ruleTypesMap = new Map(); + + this.ruleTypes.forEach((_ruleType) => { + const ruleType: RegistryRuleType = { + id: _ruleType.id, + name: _ruleType.name, + actionGroups: _ruleType.actionGroups, + recoveryActionGroup: _ruleType.recoveryActionGroup, + defaultActionGroupId: _ruleType.defaultActionGroupId, + actionVariables: _ruleType.actionVariables, + category: _ruleType.category, + producer: _ruleType.producer, + minimumLicenseRequired: _ruleType.minimumLicenseRequired, + isExportable: _ruleType.isExportable, + ruleTaskTimeout: _ruleType.ruleTaskTimeout, + defaultScheduleInterval: _ruleType.defaultScheduleInterval, + doesSetRecoveryContext: _ruleType.doesSetRecoveryContext, + enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType( + _ruleType.id, + _ruleType.name, + _ruleType.minimumLicenseRequired + ).isValid, + fieldsForAAD: _ruleType.fieldsForAAD, + hasFieldsForAAD: Boolean(_ruleType.fieldsForAAD), + hasAlertsMappings: !!_ruleType.alerts, + ...(_ruleType.alerts ? { alerts: _ruleType.alerts } : {}), + validLegacyConsumers: _ruleType.validLegacyConsumers, + }; + + ruleTypesMap.set(ruleType.id, ruleType); + }); + + return ruleTypesMap; } public getAllTypes(): string[] { diff --git a/x-pack/plugins/alerting/server/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client.mock.ts index 0616591cbe565..c7577656306d0 100644 --- a/x-pack/plugins/alerting/server/rules_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client.mock.ts @@ -5,12 +5,15 @@ * 2.0. */ +import { alertingAuthorizationMock } from './authorization/alerting_authorization.mock'; import { RulesClientApi } from './types'; type Schema = RulesClientApi; export type RulesClientMock = jest.Mocked; const createRulesClientMock = () => { + const alertingAuthorization = alertingAuthorizationMock.create(); + const mocked: RulesClientMock = { aggregate: jest.fn().mockReturnValue({ ruleExecutionStatus: {}, ruleLastRunOutcome: {} }), getTags: jest.fn(), @@ -31,10 +34,7 @@ const createRulesClientMock = () => { listRuleTypes: jest.fn(), getAlertSummary: jest.fn(), getAuditLogger: jest.fn(), - getAuthorization: jest.fn().mockImplementation(() => ({ - getFindAuthorizationFilter: jest.fn().mockReturnValue({ filter: null }), - getAuthorizedRuleTypes: jest.fn().mockResolvedValue([]), - })), + getAuthorization: jest.fn().mockReturnValue(alertingAuthorization), getExecutionLogForRule: jest.fn(), getRuleExecutionKPI: jest.fn(), getGlobalExecutionKpiWithAuth: jest.fn(), diff --git a/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts b/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts new file mode 100644 index 0000000000000..fc14cb19bb803 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts @@ -0,0 +1,463 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { nodeBuilder } from '@kbn/es-query'; +import { + buildConsumersFilter, + buildFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from './filters'; + +describe('filters', () => { + describe('combineFilterWithAuthorizationFilter', () => { + it('returns undefined if neither a filter or authorizationFilter are passed', () => { + expect(combineFilterWithAuthorizationFilter()).toBeUndefined(); + }); + + it('returns a single KueryNode when only a filter is passed in', () => { + const node = nodeBuilder.is('a', 'hello'); + expect(combineFilterWithAuthorizationFilter(node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it('returns a single KueryNode when only an authorizationFilter is passed in', () => { + const node = nodeBuilder.is('a', 'hello'); + expect(combineFilterWithAuthorizationFilter(undefined, node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it("returns a single KueryNode and'ing together the passed in parameters", () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilterWithAuthorizationFilter(node, node2)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + + it("returns a single KueryNode and'ing together the passed in parameters in opposite order", () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilterWithAuthorizationFilter(node2, node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + }); + + describe('buildFilter', () => { + it('returns undefined if filters is undefined', () => { + expect(buildFilter({ filters: undefined, field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns undefined if filters is is an empty array', () => { + expect(buildFilter({ filters: [], field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns a KueryNode using or operator', () => { + expect(buildFilter({ filters: ['value1'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it("returns multiple nodes or'd together", () => { + expect(buildFilter({ filters: ['value1', 'value2'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value2", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + + it('does not escape special kql characters in the filter values', () => { + const specialCharacters = 'awesome:()\\<>"*'; + + expect(buildFilter({ filters: [specialCharacters], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "awesome:()\\\\<>\\"*", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + }); + + describe('combineFilters', () => { + it('returns undefined if the nodes are undefined or null', () => { + expect(combineFilters([null, undefined])).toBeUndefined(); + }); + + it('combines the filters correctly', () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilters([node, null, undefined, node2])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + + it('combines the filters correctly with an operator', () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilters([node, null, undefined, node2], 'or')).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); + + describe('buildRuleTypeIdsFilter', () => { + it('returns undefined if ruleTypeIds is undefined', () => { + expect(buildRuleTypeIdsFilter()).toBeUndefined(); + }); + + it('returns undefined if ruleTypeIds is is an empty array', () => { + expect(buildRuleTypeIdsFilter([])).toBeUndefined(); + }); + + it('builds the filter correctly', () => { + expect(buildRuleTypeIdsFilter(['foo', 'bar'])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "bar", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); + + describe('buildConsumersFilter', () => { + it('returns undefined if ruleTypeIds is undefined', () => { + expect(buildConsumersFilter()).toBeUndefined(); + }); + + it('returns undefined if ruleTypeIds is is an empty array', () => { + expect(buildConsumersFilter([])).toBeUndefined(); + }); + + it('builds the filter correctly', () => { + expect(buildConsumersFilter(['foo', 'bar'])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "bar", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/rules_client/common/filters.ts b/x-pack/plugins/alerting/server/rules_client/common/filters.ts new file mode 100644 index 0000000000000..b0c3ccc5e1ec1 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/common/filters.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KueryNode, nodeBuilder } from '@kbn/es-query'; +import { RULE_SAVED_OBJECT_TYPE } from '../..'; + +export const NodeBuilderOperators = { + and: 'and', + or: 'or', +} as const; + +type NodeBuilderOperatorsType = keyof typeof NodeBuilderOperators; + +interface FilterField { + filters?: string | string[]; + field: string; + operator: NodeBuilderOperatorsType; + type?: string; +} + +export const buildFilter = ({ + filters, + field, + operator, + type = RULE_SAVED_OBJECT_TYPE, +}: FilterField): KueryNode | undefined => { + if (filters === undefined) { + return; + } + + const filtersAsArray = Array.isArray(filters) ? filters : [filters]; + + if (filtersAsArray.length === 0) { + return; + } + + return nodeBuilder[operator]( + filtersAsArray.map((filter) => nodeBuilder.is(`${type}.attributes.${field}`, filter)) + ); +}; + +export const buildRuleTypeIdsFilter = (ruleTypeIds?: string[]) => { + if (!ruleTypeIds || !ruleTypeIds?.length) { + return; + } + + return buildFilter({ filters: ruleTypeIds, field: 'alertTypeId', operator: 'or' }); +}; + +export const buildConsumersFilter = (consumers?: string[]) => { + if (!consumers || !consumers?.length) { + return; + } + + return buildFilter({ filters: consumers, field: 'consumer', operator: 'or' }); +}; + +/** + * Combines Kuery nodes and accepts an array with a mixture of undefined and KueryNodes. This will filter out the undefined + * filters and return a KueryNode with the filters combined using the specified operator which defaults to and if not defined. + */ +export function combineFilters( + nodes: Array, + operator: NodeBuilderOperatorsType = NodeBuilderOperators.and +): KueryNode | undefined { + const filters = nodes.filter(Boolean) as KueryNode[]; + + if (filters.length <= 0) { + return; + } + + return nodeBuilder[operator](filters); +} + +export const combineFilterWithAuthorizationFilter = ( + filter?: KueryNode, + authorizationFilter?: KueryNode +) => { + if (!filter && !authorizationFilter) { + return; + } + + const kueries = [ + ...(filter !== undefined ? [filter] : []), + ...(authorizationFilter !== undefined ? [authorizationFilter] : []), + ]; + return nodeBuilder.and(kueries); +}; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts b/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts index b9cc41a0fd7c4..591602effc474 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts @@ -6,11 +6,11 @@ */ import { withSpan } from '@kbn/apm-utils'; -import { AlertingAuthorizationEntity } from '../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { alertingAuthorizationFilterOpts } from '../common/constants'; import { BulkAction } from '../types'; +import { AlertingAuthorizationEntity } from '../../authorization/types'; export const getAuthorizationFilter = async ( context: RulesClientContext, @@ -20,10 +20,10 @@ export const getAuthorizationFilter = async ( const authorizationTuple = await withSpan( { name: 'authorization.getFindAuthorizationFilter', type: 'rules' }, () => - context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ) + context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }) ); return authorizationTuple.filter; } catch (error) { diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts index a7d60fc8f8ca4..4d71af6573b57 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts @@ -108,16 +108,16 @@ export async function getActionErrorLogWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts index fc2c1298f69ac..4441cc69a5f72 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts @@ -105,16 +105,16 @@ export async function getGlobalExecutionKpiWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts index 18d65c28fc9bb..95d41a02a685b 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts @@ -118,16 +118,16 @@ export async function getGlobalExecutionLogWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts new file mode 100644 index 0000000000000..f8e2beba7ee67 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionsAuthorization } from '@kbn/actions-plugin/server'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { AlertingAuthorization } from '../authorization'; +import { ConnectorAdapterRegistry } from '../connector_adapters/connector_adapter_registry'; +import type { ConstructorOptions } from './rules_client'; +import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, +} from '@kbn/core-saved-objects-api-server-mocks'; +import { auditLoggerMock } from '@kbn/core-security-server-mocks'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { alertingAuthorizationMock } from '../authorization/alerting_authorization.mock'; +import { backfillClientMock } from '../backfill_client/backfill_client.mock'; +import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; + +const create = () => { + const kibanaVersion = 'v8.17.0'; + 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 internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); + const backfillClient = backfillClientMock.create(); + + const rulesClientParams: jest.Mocked = { + taskManager, + ruleTypeRegistry, + unsecuredSavedObjectsClient, + authorization: authorization as unknown as AlertingAuthorization, + actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization, + spaceId: 'default', + namespace: 'default', + getUserName: jest.fn(), + createAPIKey: jest.fn(), + logger: loggingSystemMock.create().get(), + internalSavedObjectsRepository, + encryptedSavedObjectsClient: encryptedSavedObjects, + getActionsClient: jest.fn(), + getEventLogClient: jest.fn(), + kibanaVersion, + auditLogger, + maxScheduledPerMinute: 10000, + minimumScheduleInterval: { value: '1m', enforce: false }, + isAuthenticationTypeAPIKey: jest.fn(), + getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, + backfillClient, + isSystemAction: jest.fn(), + connectorAdapterRegistry: new ConnectorAdapterRegistry(), + uiSettings: uiSettingsServiceMock.createStartContract(), + }; + + return rulesClientParams; +}; + +export const rulesClientContextMock = { create }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts index b096ec1c75f7d..7205decb32bb5 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts @@ -17,10 +17,7 @@ import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; -import { - AlertingAuthorization, - RegistryAlertTypeWithAuth, -} from '../../authorization/alerting_authorization'; +import { AlertingAuthorization } from '../../authorization/alerting_authorization'; import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { getBeforeSetup } from './lib'; import { RecoveredActionGroup } from '../../../common'; @@ -88,6 +85,7 @@ describe('listRuleTypes', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }; + const myAppAlertType: RegistryRuleType = { actionGroups: [], actionVariables: undefined, @@ -104,7 +102,11 @@ describe('listRuleTypes', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }; - const setOfAlertTypes = new Set([myAppAlertType, alertingAlertType]); + + const setOfAlertTypes = new Map([ + [myAppAlertType.id, myAppAlertType], + [alertingAlertType.id, alertingAlertType], + ]); const authorizedConsumers = { alerts: { read: true, all: true }, @@ -118,62 +120,162 @@ describe('listRuleTypes', () => { test('should return a list of AlertTypes that exist in the registry', async () => { ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { ...myAppAlertType, authorizedConsumers }, - { ...alertingAlertType, authorizedConsumers }, + ruleTypeRegistry.has.mockReturnValue(true); + + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [myAppAlertType.id, { authorizedConsumers }], + [alertingAlertType.id, { authorizedConsumers }], ]) ); - expect(await rulesClient.listRuleTypes()).toEqual( - new Set([ - { ...myAppAlertType, authorizedConsumers }, - { ...alertingAlertType, authorizedConsumers }, + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myAppAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myAppAlertType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "alertingAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "alertingAlertType", + "producer": "alerts", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); + }); + + test('should filter out rule types that are not registered in the registry', async () => { + ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); + ruleTypeRegistry.has.mockImplementation((id: string) => id === myAppAlertType.id); + + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [myAppAlertType.id, { authorizedConsumers }], + [alertingAlertType.id, { authorizedConsumers }], ]) ); + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myAppAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myAppAlertType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); }); describe('authorization', () => { - const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - id: 'myOtherType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]); - beforeEach(() => { - ruleTypeRegistry.list.mockReturnValue(listedTypes); - }); - - test('should return a list of AlertTypes that exist in the registry only if the user is authorised to get them', async () => { - const authorizedTypes = new Set([ + const listedTypes = new Map([ + [ + 'myType', { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + 'myOtherType', + { + id: 'myOtherType', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', @@ -182,18 +284,62 @@ describe('listRuleTypes', () => { recoveryActionGroup: RecoveredActionGroup, category: 'test', producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, - }, enabledInLicense: true, hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]); - authorization.filterByRuleTypeAuthorization.mockResolvedValue(authorizedTypes); + ], + ]); + + beforeEach(() => { + ruleTypeRegistry.list.mockReturnValue(listedTypes); + ruleTypeRegistry.has.mockReturnValue(true); + }); - expect(await rulesClient.listRuleTypes()).toEqual(authorizedTypes); + test('should return a list of AlertTypes that exist in the registry only if the user is authorized to get them', async () => { + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]) + ); + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "myApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/types.ts b/x-pack/plugins/alerting/server/rules_client/types.ts index 9a701e1c95c81..afcb4e1037a6c 100644 --- a/x-pack/plugins/alerting/server/rules_client/types.ts +++ b/x-pack/plugins/alerting/server/rules_client/types.ts @@ -23,7 +23,6 @@ import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import { IEventLogClient, IEventLogger } from '@kbn/event-log-plugin/server'; import { AuditLogger } from '@kbn/security-plugin/server'; import { DistributiveOmit } from '@elastic/eui'; -import { RegistryRuleType } from '../rule_type_registry'; import { RuleTypeRegistry, IntervalSchedule, @@ -108,9 +107,6 @@ export type NormalizedAlertActionWithGeneratedValues = | NormalizedAlertDefaultActionWithGeneratedValues | NormalizedAlertSystemActionWithGeneratedValues; -export interface RegistryAlertTypeWithAuth extends RegistryRuleType { - authorizedConsumers: string[]; -} export type CreateAPIKeyResult = | { apiKeysEnabled: false } | { apiKeysEnabled: true; result: SecurityPluginGrantAPIKeyResult }; diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 4cd7ffbcf0c6c..9af5962915d72 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -98,11 +98,11 @@ test('creates a rules client with proper constructor arguments when security is const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); - alertingAuthorizationClientFactory.create.mockReturnValue( + alertingAuthorizationClientFactory.create.mockResolvedValue( alertingAuthorization as unknown as AlertingAuthorization ); - factory.create(request, savedObjectsService); + await factory.create(request, savedObjectsService); expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], @@ -154,11 +154,11 @@ test('creates a rules client with proper constructor arguments', async () => { const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); - alertingAuthorizationClientFactory.create.mockReturnValue( + alertingAuthorizationClientFactory.create.mockResolvedValue( alertingAuthorization as unknown as AlertingAuthorization ); - factory.create(request, savedObjectsService); + await factory.create(request, savedObjectsService); expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], @@ -203,7 +203,7 @@ test('creates a rules client with proper constructor arguments', async () => { test('getUserName() returns null when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const userNameResult = await constructorCall.getUserName(); @@ -216,7 +216,7 @@ test('getUserName() returns a name when security is enabled', async () => { ...rulesClientFactoryParams, securityService, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityService.authc.getCurrentUser.mockReturnValueOnce({ @@ -229,7 +229,7 @@ test('getUserName() returns a name when security is enabled', async () => { test('getActionsClient() returns ActionsClient', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const actionsClient = await constructorCall.getActionsClient(); @@ -239,7 +239,7 @@ test('getActionsClient() returns ActionsClient', async () => { test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const createAPIKeyResult = await constructorCall.createAPIKey(); @@ -249,7 +249,7 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce(null); @@ -265,7 +265,7 @@ test('createAPIKey() returns an API key when security is enabled', async () => { securityPluginSetup, securityPluginStart, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce({ @@ -296,7 +296,7 @@ test('createAPIKey() throws when security plugin createAPIKey throws an error', securityPluginSetup, securityPluginStart, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockRejectedValueOnce( diff --git a/x-pack/plugins/alerting/server/rules_client_factory.ts b/x-pack/plugins/alerting/server/rules_client_factory.ts index f28170b277ac4..f56b0840317bb 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.ts @@ -115,7 +115,10 @@ export class RulesClientFactory { this.securityService = options.securityService; } - public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient { + public async create( + request: KibanaRequest, + savedObjects: SavedObjectsServiceStart + ): Promise { const { securityPluginSetup, securityService, securityPluginStart, actions, eventLog } = this; const spaceId = this.getSpaceId(request); @@ -123,6 +126,8 @@ export class RulesClientFactory { throw new Error('AlertingAuthorizationClientFactory is not defined'); } + const authorization = await this.authorization.create(request); + return new RulesClient({ spaceId, kibanaVersion: this.kibanaVersion, @@ -139,7 +144,7 @@ export class RulesClientFactory { AD_HOC_RUN_SAVED_OBJECT_TYPE, ], }), - authorization: this.authorization.create(request), + authorization, actionsAuthorization: actions.getActionsAuthorizationWithRequest(request), namespace: this.spaceIdToNamespace(spaceId), internalSavedObjectsRepository: this.internalSavedObjectsRepository, @@ -169,6 +174,7 @@ export class RulesClientFactory { if (!createAPIKeyResult) { return { apiKeysEnabled: false }; } + return { apiKeysEnabled: true, result: createAPIKeyResult, diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts index 00f1a87aefd71..c0eb08e6d582f 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts @@ -2617,7 +2617,6 @@ describe('Action Scheduler', () => { }); expect(buildActionParams).not.toHaveBeenCalledWith(); - expect(actionsClient.ephemeralEnqueuedExecution).not.toHaveBeenCalled(); expect(actionsClient.bulkEnqueueExecution).not.toHaveBeenCalled(); expect(alertingEventLogger.logAction).not.toHaveBeenCalled(); expect(executorParams.logger.warn).toHaveBeenCalledWith( @@ -2662,7 +2661,6 @@ describe('Action Scheduler', () => { expect(res).toEqual({ throttledSummaryActions: {} }); expect(buildActionParams).not.toHaveBeenCalled(); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); - expect(actionsClient.ephemeralEnqueuedExecution).not.toHaveBeenCalled(); expect(actionsClient.bulkEnqueueExecution).not.toHaveBeenCalled(); expect(alertingEventLogger.logAction).not.toHaveBeenCalled(); }); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts index fa16cfcabb094..9a174dd236cf1 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts @@ -5,13 +5,8 @@ * 2.0. */ +import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { - createTaskRunError, - isEphemeralTaskRejectedDueToCapacityError, - TaskErrorSource, -} from '@kbn/task-manager-plugin/server'; -import { - ExecuteOptions as EnqueueExecutionOptions, ExecutionResponseItem, ExecutionResponseType, } from '@kbn/actions-plugin/server/create_execute_function'; @@ -51,8 +46,6 @@ export class ActionScheduler< IActionScheduler > = []; - private ephemeralActionsToSchedule: number; - constructor( private readonly context: ActionSchedulerOptions< Params, @@ -65,7 +58,6 @@ export class ActionScheduler< AlertData > ) { - this.ephemeralActionsToSchedule = context.taskRunnerContext.maxEphemeralActionsPerRule; for (const [_, scheduler] of Object.entries(schedulers)) { this.schedulers.push(new scheduler(context)); } @@ -101,37 +93,28 @@ export class ActionScheduler< return { throttledSummaryActions }; } - const bulkScheduleRequest: EnqueueExecutionOptions[] = []; - - for (const result of allActionsToScheduleResult) { - await this.runActionAsEphemeralOrAddToBulkScheduleRequest({ - enqueueOptions: result.actionToEnqueue, - bulkScheduleRequest, - }); - } - let bulkScheduleResponse: ExecutionResponseItem[] = []; - if (!!bulkScheduleRequest.length) { - for (const c of chunk(bulkScheduleRequest, BULK_SCHEDULE_CHUNK_SIZE)) { - let enqueueResponse; - try { - enqueueResponse = await withAlertingSpan('alerting:bulk-enqueue-actions', () => - this.context.actionsClient!.bulkEnqueueExecution(c) - ); - } catch (e) { - if (e.statusCode === 404) { - throw createTaskRunError(e, TaskErrorSource.USER); - } - throw createTaskRunError(e, TaskErrorSource.FRAMEWORK); - } - if (enqueueResponse.errors) { - bulkScheduleResponse = bulkScheduleResponse.concat( - enqueueResponse.items.filter( - (i) => i.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR - ) - ); + for (const c of chunk(allActionsToScheduleResult, BULK_SCHEDULE_CHUNK_SIZE)) { + let enqueueResponse; + try { + enqueueResponse = await withAlertingSpan('alerting:bulk-enqueue-actions', () => + this.context.actionsClient!.bulkEnqueueExecution( + c.map((actions) => actions.actionToEnqueue) + ) + ); + } catch (e) { + if (e.statusCode === 404) { + throw createTaskRunError(e, TaskErrorSource.USER); } + throw createTaskRunError(e, TaskErrorSource.FRAMEWORK); + } + if (enqueueResponse.errors) { + bulkScheduleResponse = bulkScheduleResponse.concat( + enqueueResponse.items.filter( + (i) => i.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR + ) + ); } } @@ -175,28 +158,4 @@ export class ActionScheduler< return { throttledSummaryActions }; } - - private async runActionAsEphemeralOrAddToBulkScheduleRequest({ - enqueueOptions, - bulkScheduleRequest, - }: { - enqueueOptions: EnqueueExecutionOptions; - bulkScheduleRequest: EnqueueExecutionOptions[]; - }) { - if ( - this.context.taskRunnerContext.supportsEphemeralTasks && - this.ephemeralActionsToSchedule > 0 - ) { - this.ephemeralActionsToSchedule--; - try { - await this.context.actionsClient!.ephemeralEnqueuedExecution(enqueueOptions); - } catch (err) { - if (isEphemeralTaskRejectedDueToCapacityError(err)) { - bulkScheduleRequest.push(enqueueOptions); - } - } - } else { - bulkScheduleRequest.push(enqueueOptions); - } - } } diff --git a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts index 0e0d7983e59ff..ae6467d0dcbf8 100644 --- a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts @@ -131,6 +131,7 @@ const alertsService = new AlertsService({ elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); const backfillClient = backfillClientMock.create(); const dataPlugin = dataPluginMock.createStartContract(); @@ -167,15 +168,14 @@ const taskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType kibanaBaseUrl: 'https://localhost:5601', logger, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; const mockedTaskInstance: ConcreteTaskInstance = { @@ -459,7 +459,7 @@ describe('Ad Hoc Task Runner', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts index d126151030672..c9932820ff808 100644 --- a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts @@ -185,6 +185,7 @@ export class AdHocTaskRunner implements CancellableTask { ruleLogPrefix: ruleLabel, ruleRunMetricsStore, spaceId: adHocRunData.spaceId, + isServerless: this.context.isServerless, }; const alertsClient = await initializeAlertsClient< RuleTypeParams, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts b/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts index 4690ccc653a32..c5e833dee1058 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts @@ -113,7 +113,7 @@ describe('rule_loader', () => { }); }); - test('throws when rule is not enabled', async () => { + test('throws when rule is not enabled', () => { let outcome = 'success'; try { validateRuleAndCreateFakeRequest({ @@ -128,7 +128,7 @@ describe('rule_loader', () => { expect(outcome).toBe('failure'); }); - test('throws when rule type is not enabled', async () => { + test('throws when rule type is not enabled', () => { ruleTypeRegistry.ensureRuleTypeEnabled.mockImplementation(() => { throw new Error('rule-type-not-enabled: 2112'); }); @@ -148,7 +148,7 @@ describe('rule_loader', () => { expect(outcome).toBe('failure'); }); - test('test throws when rule params fail validation', async () => { + test('test throws when rule params fail validation', () => { mockGetAlertFromRaw.mockReturnValueOnce({ name: ruleName, alertTypeId: ruleTypeId, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts index 1d218e50f927b..68c01770fd6f7 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts @@ -189,6 +189,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -231,6 +232,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -295,6 +297,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -337,6 +340,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: true, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -404,6 +408,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -465,6 +470,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -507,6 +513,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -567,6 +574,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -609,6 +617,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -669,6 +678,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -706,6 +716,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -748,6 +759,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -819,6 +831,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -861,6 +874,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -932,6 +946,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -975,6 +990,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -1036,6 +1052,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -1079,6 +1096,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -1140,6 +1158,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -1183,6 +1202,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts index c10871613ea20..5a9a88d856744 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts @@ -285,6 +285,7 @@ export class RuleTypeRunner< ...(context.queryDelaySec ? { queryDelay: context.queryDelaySec } : {}), ...(startedAtOverridden ? { forceNow: startedAt } : {}), }), + isServerless: context.isServerless, }) ) ); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index a79dfe8f59c73..bbe927833afd0 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -53,7 +53,6 @@ import { generateActionOpts, mockDate, mockedRuleTypeSavedObject, - mockRunNowResponse, ruleType, RULE_NAME, generateRunnerResult, @@ -187,37 +186,16 @@ describe('Task Runner', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; - const ephemeralTestParams: Array< - [ - nameExtension: string, - customTaskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType, - enqueueFunction: unknown, - isBulk: boolean - ] - > = [ - ['', taskRunnerFactoryInitializerParams, actionsClient.bulkEnqueueExecution, true], - [ - ' (with ephemeral support)', - { - ...taskRunnerFactoryInitializerParams, - supportsEphemeralTasks: true, - }, - actionsClient.ephemeralEnqueuedExecution, - false, - ], - ]; - beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); // clear spy mock implementations @@ -362,103 +340,95 @@ describe('Task Runner', () => { ).toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'actionsPlugin.execute is called per alert alert that is scheduled %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - internalSavedObjectsRepository, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + test('actionsPlugin.execute is called per alert alert that is scheduled', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + internalSavedObjectsRepository, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true }) + ); - expect(logger.debug).toHaveBeenCalledTimes(6); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":1,"recovered":0,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":1,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledTimes(6); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":1,"recovered":0,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":1,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - generatedActions: 1, - newAlerts: 1, - triggeredActions: 1, - status: 'active', - logAlert: 2, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.newInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts()); + testAlertingEventLogCalls({ + activeAlerts: 1, + generatedActions: 1, + newAlerts: 1, + triggeredActions: 1, + status: 'active', + logAlert: 2, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.newInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts()); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); test('actionsPlugin.execute is skipped if muteAll is true', async () => { taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); @@ -493,7 +463,6 @@ describe('Task Runner', () => { }); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); expect(logger.debug).toHaveBeenCalledTimes(7); expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { @@ -632,7 +601,6 @@ describe('Task Runner', () => { const expectedExecutions = shouldBeSnoozed ? 0 : 1; expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(expectedExecutions); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); const expectedMessage = `no scheduling of actions for rule test:1: '${RULE_NAME}': rule is snoozed.`; if (expectedExecutions) { @@ -688,7 +656,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -760,7 +727,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -823,7 +789,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -854,202 +819,10 @@ describe('Task Runner', () => { expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'skips firing actions for active alert if alert is muted %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - ( - customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType - ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - internalSavedObjectsRepository, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - mutedInstanceIds: ['2'], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 2 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"},{\"instanceId\":\"2\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":2,"new":2,"recovered":0,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":2,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":2,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); - - test.each(ephemeralTestParams)( - 'skips firing actions for active alert if alert is throttled %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - ( - customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType - ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '2': { - meta: { - lastScheduledActions: { date: moment().toISOString(), group: 'default' }, - }, - state: { - bar: false, - start: DATE_1969, - duration: MOCK_DURATION, - }, - }, - }, - }, - }, - context: taskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - notifyWhen: 'onThrottleInterval', - throttle: '1d', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - // expect(enqueueFunction).toHaveBeenCalledTimes(1); - - // expect(logger.debug).toHaveBeenCalledTimes(5); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is throttled`, - { tags: ['1', 'test'] } - ); - } - ); - - test.each(ephemeralTestParams)( - 'skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - mutedInstanceIds: ['2'], - notifyWhen: 'onActionGroupChange', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, - { tags: ['1', 'test'] } - ); - } - ); - - test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert state does not change', async () => { - taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + test('skips firing actions for active alert if alert is muted', async () => { + ( + taskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType + ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); ruleType.executor.mockImplementation( async ({ @@ -1063,13 +836,188 @@ describe('Task Runner', () => { RuleAlertData >) => { executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); return { state: {} }; } ); const taskRunner = new TaskRunner({ ruleType, - internalSavedObjectsRepository, - taskInstance: { + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + internalSavedObjectsRepository, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + mutedInstanceIds: ['2'], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 2 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"},{\"instanceId\":\"2\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":2,"new":2,"recovered":0,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":2,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":2,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); + + test('skips firing actions for active alert if alert is throttled', async () => { + ( + taskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType + ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '2': { + meta: { + lastScheduledActions: { date: moment().toISOString(), group: 'default' }, + }, + state: { + bar: false, + start: DATE_1969, + duration: MOCK_DURATION, + }, + }, + }, + }, + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + notifyWhen: 'onThrottleInterval', + throttle: '1d', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + // expect(enqueueFunction).toHaveBeenCalledTimes(1); + + // expect(logger.debug).toHaveBeenCalledTimes(5); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is throttled`, + { tags: ['1', 'test'] } + ); + }); + + test('skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + mutedInstanceIds: ['2'], + notifyWhen: 'onActionGroupChange', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, + { tags: ['1', 'test'] } + ); + }); + + test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert state does not change', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { ...mockedTaskInstance, state: { ...mockedTaskInstance.state, @@ -1098,7 +1046,6 @@ describe('Task Runner', () => { }); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -1117,690 +1064,620 @@ describe('Task Runner', () => { expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'actionsPlugin.execute is called when notifyWhen=onActionGroupChange and alert state has changed %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { - meta: { - lastScheduledActions: { group: 'newGroup', date: new Date().toISOString() }, - }, - state: { bar: false }, + test('actionsPlugin.execute is called when notifyWhen=onActionGroupChange and alert state has changed', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { + meta: { + lastScheduledActions: { group: 'newGroup', date: new Date().toISOString() }, }, + state: { bar: false }, }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - notifyWhen: 'onActionGroupChange', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + notifyWhen: 'onActionGroupChange', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); + await taskRunner.run(); - testAlertingEventLogCalls({ - activeAlerts: 1, - triggeredActions: 1, - generatedActions: 1, - status: 'active', - logAlert: 1, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { bar: false }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + testAlertingEventLogCalls({ + activeAlerts: 1, + triggeredActions: 1, + generatedActions: 1, + status: 'active', + logAlert: 1, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { bar: false }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'includes the apiKey in the request used to initialize the actionsClient %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + test('includes the apiKey in the request used to initialize the actionsClient', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect( - customTaskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest - ).toHaveBeenCalledWith( - expect.objectContaining({ - headers: { - // base64 encoded "123:abc" - authorization: 'ApiKey MTIzOmFiYw==', - }, - }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect( + taskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest + ).toHaveBeenCalledWith( + expect.objectContaining({ + headers: { + // base64 encoded "123:abc" + authorization: 'ApiKey MTIzOmFiYw==', + }, + }) + ); - const [request] = - customTaskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest.mock - .calls[0]; + const [request] = + taskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest.mock.calls[0]; - expect(customTaskRunnerFactoryInitializerParams.basePathService.set).toHaveBeenCalledWith( - request, - '/' - ); + expect(taskRunnerFactoryInitializerParams.basePathService.set).toHaveBeenCalledWith( + request, + '/' + ); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true }) - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true }) + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - newAlerts: 1, - triggeredActions: 1, - generatedActions: 1, - status: 'active', - logAlert: 2, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.newInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + testAlertingEventLogCalls({ + activeAlerts: 1, + newAlerts: 1, + triggeredActions: 1, + generatedActions: 1, + status: 'active', + logAlert: 2, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.newInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'fire recovered actions for execution for the alertInstances which is in the recovered state %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test('fire recovered actions for execution for the alertInstances which is in the recovered state', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { - meta: {}, - state: { - bar: false, - start: DATE_1969, - duration: '80000000000', - }, + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { + meta: {}, + state: { + bar: false, + start: DATE_1969, + duration: '80000000000', }, - '2': { - meta: {}, - state: { - bar: false, - start: '1969-12-31T06:00:00.000Z', - duration: '70000000000', - }, + }, + '2': { + meta: {}, + state: { + bar: false, + start: '1969-12-31T06:00:00.000Z', + duration: '70000000000', }, }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - duration: MOCK_DURATION, - start: DATE_1969, - flappingHistory: [false], - }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + duration: MOCK_DURATION, + start: DATE_1969, + flappingHistory: [false], + }) + ); - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.recoveredInstance, - id: '2', - state: { - bar: false, - start: '1969-12-31T06:00:00.000Z', - duration: '64800000000000', - end: DATE_1970, - }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { bar: false, start: DATE_1969, duration: MOCK_DURATION }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( - 2, - generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered', uuid: '222-222' }) - ); + testAlertingEventLogCalls({ + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.recoveredInstance, + id: '2', + state: { + bar: false, + start: '1969-12-31T06:00:00.000Z', + duration: '64800000000000', + end: DATE_1970, + }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { bar: false, start: DATE_1969, duration: MOCK_DURATION }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( + 2, + generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered', uuid: '222-222' }) + ); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - expect(enqueueFunction).toHaveBeenCalledWith( - isBulk - ? [ - generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ - isBulk: false, - id: '2', - isResolved: true, - uuid: '222-222', - }), - ] - : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - jest.resetAllMocks(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith([ + generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), + ]); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + jest.resetAllMocks(); + }); - test.each(ephemeralTestParams)( - "should skip alertInstances which weren't active on the previous execution %s", - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test("should skip alertInstances which weren't active on the previous execution", async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); - // create an instance, but don't schedule any actions, so it doesn't go active - executorServices.alertFactory.create('3'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { meta: {}, state: { bar: false } }, - '2': { meta: {}, state: { bar: false } }, - }, + // create an instance, but don't schedule any actions, so it doesn't go active + executorServices.alertFactory.create('3'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { meta: {}, state: { bar: false } }, + '2': { meta: {}, state: { bar: false } }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); - - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - flappingHistory: [false], - }) - ); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledWith( - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + flappingHistory: [false], + }) + ); - expect(logger.debug).nthCalledWith( - 3, - `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - `deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - `ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}`, - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledWith( + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); + expect(logger.debug).nthCalledWith( + 3, + `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + `deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + `ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}`, + { tags: ['1', 'test'] } + ); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - if (isBulk) { - expect((enqueueFunction as jest.Mock).mock.calls[0][0][0].id).toEqual('1'); - expect((enqueueFunction as jest.Mock).mock.calls[0][0][1].id).toEqual('2'); - } else { - expect((enqueueFunction as jest.Mock).mock.calls[0][0].id).toEqual('1'); - expect((enqueueFunction as jest.Mock).mock.calls[1][0].id).toEqual('2'); - } - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + testAlertingEventLogCalls({ + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); - test.each(ephemeralTestParams)( - 'fire actions under a custom recovery group when specified on an alert type for alertInstances which are in the recovered state %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect((actionsClient.bulkEnqueueExecution as jest.Mock).mock.calls[0][0][0].id).toEqual('1'); + expect((actionsClient.bulkEnqueueExecution as jest.Mock).mock.calls[0][0][1].id).toEqual('2'); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test('fire actions under a custom recovery group when specified on an alert type for alertInstances which are in the recovered state', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - const recoveryActionGroup = { - id: 'customRecovered', - name: 'Custom Recovered', - }; - const ruleTypeWithCustomRecovery = { - ...ruleType, - recoveryActionGroup, - actionGroups: [{ id: 'default', name: 'Default' }, recoveryActionGroup], - }; + const recoveryActionGroup = { + id: 'customRecovered', + name: 'Custom Recovered', + }; + const ruleTypeWithCustomRecovery = { + ...ruleType, + recoveryActionGroup, + actionGroups: [{ id: 'default', name: 'Default' }, recoveryActionGroup], + }; - ruleTypeWithCustomRecovery.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType: ruleTypeWithCustomRecovery, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { meta: {}, state: { bar: false } }, - '2': { meta: {}, state: { bar: false } }, - }, + ruleTypeWithCustomRecovery.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType: ruleTypeWithCustomRecovery, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { meta: {}, state: { bar: false } }, + '2': { meta: {}, state: { bar: false } }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'action', - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'action', + params: { + foo: true, }, - { - group: recoveryActionGroup.id, - id: '2', - actionTypeId: 'action', - params: { - isResolved: true, - }, - uuid: '222-222', + uuid: '111-111', + }, + { + group: recoveryActionGroup.id, + id: '2', + actionTypeId: 'action', + params: { + isResolved: true, }, - ], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - flappingHistory: [false], - }) - ); + uuid: '222-222', + }, + ], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + flappingHistory: [false], + }) + ); - testAlertingEventLogCalls({ - ruleTypeDef: ruleTypeWithCustomRecovery, - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); + testAlertingEventLogCalls({ + ruleTypeDef: ruleTypeWithCustomRecovery, + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - expect(enqueueFunction).toHaveBeenCalledWith( - isBulk - ? [ - generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ - isBulk: false, - id: '2', - isResolved: true, - uuid: '222-222', - }), - ] - : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith([ + generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), + ]); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'triggers summary actions (Per rule run)', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation(async () => { - return { state: {} }; - }); + test('triggers summary actions (Per rule run)', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation(async () => { + return { state: {} }; + }); - alertsClient.getProcessedAlerts.mockReturnValue({}); - alertsClient.getSummarizedAlerts.mockResolvedValue({ - new: { - count: 1, - data: [mockAAD], - }, - ongoing: { count: 0, data: [] }, - recovered: { count: 0, data: [] }, - }); - alertsService.createAlertsClient.mockImplementation(() => alertsClient); + alertsClient.getProcessedAlerts.mockReturnValue({}); + alertsClient.getSummarizedAlerts.mockResolvedValue({ + new: { + count: 1, + data: [mockAAD], + }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }); + alertsService.createAlertsClient.mockImplementation(() => alertsClient); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'slack', - frequency: { - notifyWhen: 'onActiveAlert', - summary: true, - throttle: null, - }, - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'slack', + frequency: { + notifyWhen: 'onActiveAlert', + summary: true, + throttle: null, }, - ], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); + params: { + foo: true, + }, + uuid: '111-111', + }, + ], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true, actionTypeId: 'slack' }) - ); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true, actionTypeId: 'slack' }) + ); + }); - test.each(ephemeralTestParams)( - 'triggers summary actions (Custom Frequency)', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation(async () => { - return { state: {} }; - }); - alertsClient.getProcessedAlerts.mockReturnValue({}); - alertsClient.getSummarizedAlerts.mockResolvedValue({ - new: { - count: 1, - data: [mockAAD], - }, - ongoing: { count: 0, data: [] }, - recovered: { count: 0, data: [] }, - }); + test('triggers summary actions (Custom Frequency)', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation(async () => { + return { state: {} }; + }); + alertsClient.getProcessedAlerts.mockReturnValue({}); + alertsClient.getSummarizedAlerts.mockResolvedValue({ + new: { + count: 1, + data: [mockAAD], + }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }); - alertsClient.getAlertsToSerialize.mockResolvedValueOnce({ state: {}, meta: {} }); - alertsService.createAlertsClient.mockImplementation(() => alertsClient); + alertsClient.getAlertsToSerialize.mockResolvedValueOnce({ state: {}, meta: {} }); + alertsService.createAlertsClient.mockImplementation(() => alertsClient); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'slack', - frequency: { - notifyWhen: 'onThrottleInterval', - summary: true, - throttle: '1h', - }, - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'slack', + frequency: { + notifyWhen: 'onThrottleInterval', + summary: true, + throttle: '1h', }, - ], - }); + params: { + foo: true, + }, + uuid: '111-111', + }, + ], + }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const result = await taskRunner.run(); - - expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ - start: new Date('1969-12-31T23:00:00.000Z'), - end: new Date(DATE_1970), - ruleId: '1', - spaceId: 'default', - excludedAlertInstanceIds: [], - }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const result = await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true, actionTypeId: 'slack' }) - ); - expect(result.state.summaryActions).toEqual({ - '111-111': { date: new Date(DATE_1970).toISOString() }, - }); - } - ); + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ + start: new Date('1969-12-31T23:00:00.000Z'), + end: new Date(DATE_1970), + ruleId: '1', + spaceId: 'default', + excludedAlertInstanceIds: [], + }); + + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true, actionTypeId: 'slack' }) + ); + expect(result.state.summaryActions).toEqual({ + '111-111': { date: new Date(DATE_1970).toISOString() }, + }); + }); test('persists alertInstances passed in from state, only if they are scheduled for execution', async () => { ruleType.executor.mockImplementation( @@ -2628,7 +2505,6 @@ describe('Task Runner', () => { }, context: { ...taskRunnerFactoryInitializerParams, - supportsEphemeralTasks: true, }, inMemoryMetrics, }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 89432e1822029..cd351054f9937 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -317,6 +317,7 @@ export class TaskRunner< ruleLogPrefix: ruleLabel, ruleRunMetricsStore, spaceId, + isServerless: this.context.isServerless, }; const alertsClient = await withAlertingSpan('alerting:initialize-alerts-client', () => initializeAlertsClient< diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index 958ecaf8d270d..3d0cd5ab05059 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -216,15 +216,14 @@ describe('Task Runner', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; describe(`using ${label} for alert indices`, () => { @@ -412,6 +411,7 @@ describe('Task Runner', () => { elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); elasticsearchAndSOAvailability$.next(true); @@ -544,6 +544,7 @@ describe('Task Runner', () => { elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); elasticsearchAndSOAvailability$.next(true); @@ -590,7 +591,7 @@ describe('Task Runner', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index c96a3f95c636e..54faa13de8352 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -149,15 +149,14 @@ describe('Task Runner Cancel', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index ed4b5a0802232..94acd3a0b2db6 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -120,15 +120,14 @@ describe('Task Runner Factory', () => { logger: loggingSystemMock.create().get(), maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry: ruleTypeRegistryMock.create(), rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: true, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/task_runner/types.ts b/x-pack/plugins/alerting/server/task_runner/types.ts index a92ee2a89d654..f3e08aff2c3b7 100644 --- a/x-pack/plugins/alerting/server/task_runner/types.ts +++ b/x-pack/plugins/alerting/server/task_runner/types.ts @@ -146,6 +146,7 @@ export interface RuleTypeRunnerContext { ruleLogPrefix: string; ruleRunMetricsStore: RuleRunMetricsStore; spaceId: string; + isServerless: boolean; } export interface RuleRunnerErrorStackTraceLog { @@ -171,13 +172,12 @@ export interface TaskRunnerContext { logger: Logger; maintenanceWindowsService: MaintenanceWindowsService; maxAlerts: number; - maxEphemeralActionsPerRule: number; ruleTypeRegistry: RuleTypeRegistry; rulesSettingsService: RulesSettingsService; savedObjects: SavedObjectsServiceStart; share: SharePluginStart; spaceIdToNamespace: SpaceIdToNamespaceFunction; - supportsEphemeralTasks: boolean; uiSettings: UiSettingsServiceStart; usageCounter?: UsageCounter; + isServerless: boolean; } diff --git a/x-pack/plugins/alerting/server/test_utils/index.ts b/x-pack/plugins/alerting/server/test_utils/index.ts index 036454f2f80c6..401225f171f06 100644 --- a/x-pack/plugins/alerting/server/test_utils/index.ts +++ b/x-pack/plugins/alerting/server/test_utils/index.ts @@ -57,7 +57,6 @@ export function generateAlertingConfig(): AlertingConfig { interval: '5m', removalDelay: '1h', }, - maxEphemeralActionsPerAlert: 10, cancelAlertsOnRuleTimeout: true, rules: { maxScheduledPerMinute: 10000, diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index b660d348b9e06..4c3d9ee57f51d 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -29,7 +29,7 @@ import { Alert } from '@kbn/alerts-as-data-utils'; import { ActionsApiRequestHandlerContext } from '@kbn/actions-plugin/server'; import { AlertsHealth } from '@kbn/alerting-types'; import { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry'; -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { AlertingServerSetup, AlertingServerStart } from './plugin'; import { RulesClient } from './rules_client'; import { RulesSettingsClient, @@ -62,7 +62,7 @@ export type { RuleTypeParams }; * @public */ export interface AlertingApiRequestHandlerContext { - getRulesClient: () => RulesClient; + getRulesClient: () => Promise; getRulesSettingsClient: (withoutAuth?: boolean) => RulesSettingsClient; getMaintenanceWindowClient: () => MaintenanceWindowClient; listTypes: RuleTypeRegistry['list']; @@ -133,6 +133,7 @@ export interface RuleExecutorOptions< namespace?: string; flappingSettings: RulesSettingsFlappingProperties; getTimeRange: (timeWindow?: string) => GetTimeRangeResult; + isServerless: boolean; } export interface RuleParamsAndRefs { @@ -361,8 +362,8 @@ export type PartialRuleWithLegacyId = Pic Partial, 'id'>>; export interface AlertingPlugin { - setup: PluginSetupContract; - start: PluginStartContract; + setup: AlertingServerSetup; + start: AlertingServerStart; } export interface AlertsConfigType { diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index d261a00db74ca..6019f8711d681 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -70,9 +70,11 @@ "@kbn/search-types", "@kbn/alerting-state-types", "@kbn/core-security-server", + "@kbn/security-plugin-types-server", "@kbn/core-http-server", "@kbn/zod", "@kbn/core-saved-objects-base-server-internal", + "@kbn/core-security-server-mocks", "@kbn/response-ops-rule-params", "@kbn/core-http-server-utils" ], diff --git a/x-pack/plugins/asset_inventory/README.md b/x-pack/plugins/asset_inventory/README.md new file mode 100755 index 0000000000000..e1dd9d4ac8900 --- /dev/null +++ b/x-pack/plugins/asset_inventory/README.md @@ -0,0 +1,13 @@ +# Asset Inventory Kibana Plugin + +Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. + +## Testing + +For general guidelines, read [Kibana Testing Guide](https://www.elastic.co/guide/en/kibana/current/development-tests.html) for more details diff --git a/x-pack/plugins/asset_inventory/common/index.ts b/x-pack/plugins/asset_inventory/common/index.ts new file mode 100644 index 0000000000000..9f5311be877cc --- /dev/null +++ b/x-pack/plugins/asset_inventory/common/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 const PLUGIN_ID = 'assetInventory'; +export const PLUGIN_NAME = 'assetInventory'; diff --git a/x-pack/plugins/asset_inventory/kibana.jsonc b/x-pack/plugins/asset_inventory/kibana.jsonc new file mode 100644 index 0000000000000..dbb813be7aa4e --- /dev/null +++ b/x-pack/plugins/asset_inventory/kibana.jsonc @@ -0,0 +1,17 @@ +{ + "type": "plugin", + "id": "@kbn/asset-inventory-plugin", + "owner": ["@elastic/kibana-cloud-security-posture"], + "group": "security", + "visibility": "private", + "description": "Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments", + "plugin": { + "id": "assetInventory", + "browser": true, + "server": true, + "configPath": ["xpack", "assetInventory"], + "requiredPlugins": [], + "requiredBundles": [], + "optionalPlugins": [] + } +} diff --git a/x-pack/plugins/asset_inventory/package.json b/x-pack/plugins/asset_inventory/package.json new file mode 100644 index 0000000000000..7abfb7bf63378 --- /dev/null +++ b/x-pack/plugins/asset_inventory/package.json @@ -0,0 +1,7 @@ +{ + "author": "Elastic", + "name": "@kbn/asset-inventory-plugin", + "version": "1.0.0", + "private": true, + "license": "Elastic License 2.0" +} diff --git a/x-pack/plugins/asset_inventory/public/application.tsx b/x-pack/plugins/asset_inventory/public/application.tsx new file mode 100644 index 0000000000000..f442f01d17f7c --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/application.tsx @@ -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 React from 'react'; +import ReactDOM from 'react-dom'; +import type { AppMountParameters, CoreStart } from '@kbn/core/public'; +import type { AppPluginStartDependencies } from './types'; +import { AssetInventoryApp } from './components/app'; + +export const renderApp = ( + { notifications, http }: CoreStart, + {}: AppPluginStartDependencies, + { appBasePath, element }: AppMountParameters +) => { + ReactDOM.render( + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/plugins/asset_inventory/public/components/app.tsx b/x-pack/plugins/asset_inventory/public/components/app.tsx new file mode 100644 index 0000000000000..924091034353b --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/components/app.tsx @@ -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 React from 'react'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; +import { BrowserRouter as Router } from '@kbn/shared-ux-router'; +import { EuiPageTemplate, EuiTitle } from '@elastic/eui'; +import type { CoreStart } from '@kbn/core/public'; + +interface AssetInventoryAppDeps { + basename: string; + notifications: CoreStart['notifications']; + http: CoreStart['http']; +} + +export const AssetInventoryApp = ({ basename }: AssetInventoryAppDeps) => { + return ( + + + <> + + + +

        + +

        +
        +
        + +
        + +
        +
        + ); +}; diff --git a/x-pack/plugins/asset_inventory/public/index.ts b/x-pack/plugins/asset_inventory/public/index.ts new file mode 100644 index 0000000000000..269cab2ad181a --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/index.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 { AssetInventoryPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new AssetInventoryPlugin(); +} +export type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; diff --git a/x-pack/plugins/asset_inventory/public/plugin.ts b/x-pack/plugins/asset_inventory/public/plugin.ts new file mode 100644 index 0000000000000..fd2841f5b2335 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/plugin.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 type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { + AssetInventoryPluginSetup, + AssetInventoryPluginStart, + AppPluginStartDependencies, +} from './types'; + +export class AssetInventoryPlugin + implements Plugin +{ + public setup(core: CoreSetup): AssetInventoryPluginSetup { + return {}; + } + public start( + coreStart: CoreStart, + depsStart: AppPluginStartDependencies + ): AssetInventoryPluginStart { + return { + getAssetInventoryPage: async (params: AppMountParameters) => { + // Load application bundle + const { renderApp } = await import('./application'); + // Render the application + return renderApp(coreStart, depsStart as AppPluginStartDependencies, params); + }, + }; + } + + public stop() {} +} diff --git a/x-pack/plugins/asset_inventory/public/types.ts b/x-pack/plugins/asset_inventory/public/types.ts new file mode 100644 index 0000000000000..a551b4d231c3d --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AppPluginStartDependencies {} diff --git a/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts b/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts new file mode 100644 index 0000000000000..0d3d0e8f8e0c4 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { transformError } from '@kbn/securitysolution-es-utils'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { errors } from '@elastic/elasticsearch'; + +// TODO: Move transforms to integration package +export const initializeTransforms = async ( + esClient: ElasticsearchClient, + logger: Logger +): Promise => { + // Deletes old assets from previous versions as part of upgrade process + await deletePreviousTransformsVersions(esClient, logger); + // TODO initialize transforms here + // await initializeTransform(esClient, , logger); +}; + +export const initializeTransform = async ( + esClient: ElasticsearchClient, + transform: TransformPutTransformRequest, + logger: Logger +) => { + const success = await createTransformIfNotExists(esClient, transform, logger); + + if (success) { + await startTransformIfNotStarted(esClient, transform.transform_id, logger); + } +}; + +/** + * Checks if a transform exists, And if not creates it + * + * @param transform - the transform to create. If a transform with the same transform_id already exists, nothing is created or updated. + * + * @return true if the transform exits or created, false otherwise. + */ +export const createTransformIfNotExists = async ( + esClient: ElasticsearchClient, + transform: TransformPutTransformRequest, + logger: Logger +) => { + try { + await esClient.transform.getTransform({ + transform_id: transform.transform_id, + }); + return true; + } catch (existErr) { + const existError = transformError(existErr); + if (existError.statusCode === 404) { + try { + await esClient.transform.putTransform(transform); + return true; + } catch (createErr) { + const createError = transformError(createErr); + logger.error( + `Failed to create transform ${transform.transform_id}: ${createError.message}` + ); + } + } else { + logger.error( + `Failed to check if transform ${transform.transform_id} exists: ${existError.message}` + ); + } + } + return false; +}; + +export const startTransformIfNotStarted = async ( + esClient: ElasticsearchClient, + transformId: string, + logger: Logger +) => { + try { + const transformStats = await esClient.transform.getTransformStats({ + transform_id: transformId, + }); + + if (transformStats.count <= 0) { + logger.error(`Failed starting transform ${transformId}: couldn't find transform`); + return; + } + + const fetchedTransformStats = transformStats.transforms[0]; + + // trying to restart the transform in case it comes to a full stop or failure + if (fetchedTransformStats.state === 'stopped' || fetchedTransformStats.state === 'failed') { + try { + return await esClient.transform.startTransform({ transform_id: transformId }); + } catch (startErr) { + const startError = transformError(startErr); + logger.error( + `Failed to start transform ${transformId}. Transform State: Transform State: ${fetchedTransformStats.state}. Error: ${startError.message}` + ); + } + } + + if (fetchedTransformStats.state === 'stopping' || fetchedTransformStats.state === 'aborting') { + logger.error( + `Not starting transform ${transformId} since it's state is: ${fetchedTransformStats.state}` + ); + } + } catch (statsErr) { + const statsError = transformError(statsErr); + logger.error(`Failed to check if transform ${transformId} is started: ${statsError.message}`); + } +}; + +const deletePreviousTransformsVersions = async (esClient: ElasticsearchClient, logger: Logger) => { + // TODO Concat all deprecated transforms versions + const deprecatedTransforms: string[] = []; + + for (const transform of deprecatedTransforms) { + const response = await deleteTransformSafe(esClient, logger, transform); + if (response) return; + } +}; + +const deleteTransformSafe = async ( + esClient: ElasticsearchClient, + logger: Logger, + name: string +): Promise => { + try { + await esClient.transform.deleteTransform({ transform_id: name, force: true }); + logger.info(`Deleted transform successfully [Name: ${name}]`); + return true; + } catch (e) { + if (e instanceof errors.ResponseError && e.statusCode === 404) { + logger.trace(`Transform not exists [Name: ${name}]`); + return false; + } else { + logger.error(`Failed to delete transform [Name: ${name}]`); + logger.error(e); + return false; + } + } +}; diff --git a/x-pack/plugins/asset_inventory/server/index.ts b/x-pack/plugins/asset_inventory/server/index.ts new file mode 100644 index 0000000000000..6306618078898 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/index.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. + */ +import type { PluginInitializerContext } from '@kbn/core/server'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export async function plugin(initializerContext: PluginInitializerContext) { + const { AssetInventoryPlugin } = await import('./plugin'); + return new AssetInventoryPlugin(initializerContext); +} + +export type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; diff --git a/x-pack/plugins/asset_inventory/server/plugin.ts b/x-pack/plugins/asset_inventory/server/plugin.ts new file mode 100644 index 0000000000000..3f35991c379d5 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/plugin.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '@kbn/core/server'; + +import type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; +import { defineRoutes } from './routes'; +// TODO Uncomment this line when initialize() is enabled +// import { initializeTransforms } from './create_transforms/create_transforms'; + +export class AssetInventoryPlugin + implements Plugin +{ + private readonly logger: Logger; + + // TODO Uncomment this line when initialize() is enabled + // private isInitialized: boolean = false; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('assetInventory: Setup'); + const router = core.http.createRouter(); + + // Register server side APIs + defineRoutes(router); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('assetInventory: Started'); + + // TODO Invoke initialize() when it's due + // this.initialize(core).catch(() => {}); + + return {}; + } + + public stop() {} + + /** + * Initialization is idempotent and required for (re)creating indices and transforms. + */ + // TODO Uncomment these lines when initialize() is enabled + // async initialize(core: CoreStart): Promise { + // this.logger.debug('initialize'); + // const esClient = core.elasticsearch.client.asInternalUser; + // await initializeTransforms(esClient, this.logger); + // this.isInitialized = true; + // } +} diff --git a/x-pack/plugins/asset_inventory/server/routes/index.ts b/x-pack/plugins/asset_inventory/server/routes/index.ts new file mode 100644 index 0000000000000..f577bfa19f719 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/routes/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { IRouter } from '@kbn/core/server'; + +export function defineRoutes(router: IRouter) { + router.get( + { + path: '/api/asset_inventory/example', + validate: false, + }, + async (context, request, response) => { + return response.ok({ + body: { + time: new Date().toISOString(), + }, + }); + } + ); +} diff --git a/x-pack/plugins/asset_inventory/server/types.ts b/x-pack/plugins/asset_inventory/server/types.ts new file mode 100644 index 0000000000000..1d9380e8514f8 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginStart {} diff --git a/x-pack/plugins/asset_inventory/tsconfig.json b/x-pack/plugins/asset_inventory/tsconfig.json new file mode 100644 index 0000000000000..dc669eb3a6943 --- /dev/null +++ b/x-pack/plugins/asset_inventory/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "common/**/*.ts", + "common/**/*.json", + "public/**/*.ts", + "public/**/*.tsx", + "public/**/*.json", + "server/**/*.ts", + "server/**/*.json", + "../../../typings/**/*" + ], + "exclude": ["target/**/*"], + "kbn_references": [ + "@kbn/core", + "@kbn/i18n-react", + "@kbn/shared-ux-router", + "@kbn/securitysolution-es-utils" + ] +} diff --git a/x-pack/plugins/cases/common/constants/owner.test.ts b/x-pack/plugins/cases/common/constants/owner.test.ts index 07b6866f857a4..b53f177dd7d29 100644 --- a/x-pack/plugins/cases/common/constants/owner.test.ts +++ b/x-pack/plugins/cases/common/constants/owner.test.ts @@ -10,7 +10,11 @@ import { OWNER_INFO } from './owners'; describe('OWNER_INFO', () => { it('should use all available rule consumers', () => { - const allConsumers = new Set(Object.values(AlertConsumers)); + const allConsumers = new Set( + // Alerts consumer fallbacks to producer so it is not counted as valid one + Object.values(AlertConsumers).filter((consumer) => consumer !== AlertConsumers.ALERTS) + ); + const ownersMappingConsumers = new Set( Object.values(OWNER_INFO) .map((value) => value.validRuleConsumers ?? []) diff --git a/x-pack/plugins/cases/common/constants/owners.ts b/x-pack/plugins/cases/common/constants/owners.ts index a7628628a7dcc..79db38345e566 100644 --- a/x-pack/plugins/cases/common/constants/owners.ts +++ b/x-pack/plugins/cases/common/constants/owners.ts @@ -59,6 +59,11 @@ export const OWNER_INFO: Record = { label: 'Management', iconType: 'managementApp', appRoute: '/app/management/insightsAndAlerting', - validRuleConsumers: [AlertConsumers.ML, AlertConsumers.STACK_ALERTS, AlertConsumers.EXAMPLE], + validRuleConsumers: [ + AlertConsumers.ML, + AlertConsumers.STACK_ALERTS, + AlertConsumers.EXAMPLE, + AlertConsumers.DISCOVER, + ], }, } as const; diff --git a/x-pack/plugins/cases/common/utils/owner.test.ts b/x-pack/plugins/cases/common/utils/owner.test.ts index a6f7c99f540bb..4e005750ad36f 100644 --- a/x-pack/plugins/cases/common/utils/owner.test.ts +++ b/x-pack/plugins/cases/common/utils/owner.test.ts @@ -40,7 +40,7 @@ describe('owner utils', () => { validRuleConsumers: item.validRuleConsumers, })); - it.each(owners)('returns owner %s correctly for consumer', (owner) => { + it.each(owners)('returns owner %j correctly for consumer', (owner) => { for (const consumer of owner.validRuleConsumers ?? []) { const result = getOwnerFromRuleConsumerProducer({ consumer }); @@ -48,7 +48,7 @@ describe('owner utils', () => { } }); - it.each(owners)('returns owner %s correctly for producer', (owner) => { + it.each(owners)('returns owner %j correctly for producer', (owner) => { for (const producer of owner.validRuleConsumers ?? []) { const result = getOwnerFromRuleConsumerProducer({ producer }); @@ -80,5 +80,14 @@ describe('owner utils', () => { expect(owner).toBe(OWNER_INFO.securitySolution.id); }); + + it('fallbacks to producer when the consumer is alerts', () => { + const owner = getOwnerFromRuleConsumerProducer({ + consumer: AlertConsumers.ALERTS, + producer: AlertConsumers.OBSERVABILITY, + }); + + expect(owner).toBe(OWNER_INFO.observability.id); + }); }); }); diff --git a/x-pack/plugins/cases/common/utils/owner.ts b/x-pack/plugins/cases/common/utils/owner.ts index 7bde7220233db..d159a3d55ee7a 100644 --- a/x-pack/plugins/cases/common/utils/owner.ts +++ b/x-pack/plugins/cases/common/utils/owner.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AlertConsumers } from '@kbn/rule-data-utils'; import { OWNER_INFO } from '../constants'; import type { Owner } from '../constants/types'; @@ -29,9 +30,12 @@ export const getOwnerFromRuleConsumerProducer = ({ return OWNER_INFO.securitySolution.id; } + // Fallback to producer if the consumer is alerts + const consumerValue = consumer === AlertConsumers.ALERTS ? producer : consumer; + for (const value of Object.values(OWNER_INFO)) { const foundConsumer = value.validRuleConsumers?.find( - (validConsumer) => validConsumer === consumer || validConsumer === producer + (validConsumer) => validConsumer === consumerValue || validConsumer === producer ); if (foundConsumer) { diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx index 550240060ddf6..fc50c7a61a64a 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx @@ -83,12 +83,13 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "assignees", "name": "Assignees", "render": [Function], + "width": "10%", }, Object { "field": "tags", @@ -101,50 +102,54 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "closedAt", "name": "Closed on", "render": [Function], "sortable": true, + "width": "10%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -185,12 +190,13 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "assignees", "name": "Assignees", "render": [Function], + "width": "10%", }, Object { "field": "tags", @@ -203,44 +209,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -291,13 +300,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -309,6 +319,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -340,13 +351,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -358,6 +370,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -389,13 +402,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -407,6 +421,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -430,7 +445,7 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "tags", @@ -443,44 +458,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -538,7 +556,7 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "tags", @@ -551,44 +569,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index efdc443366886..73292ac9d71bd 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -122,7 +122,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: !isSelectorView ? '20%' : '55%', + width: !isSelectorView ? '17%' : '55%', }, assignees: { field: casesColumnsConfig.assignees.field, @@ -130,6 +130,7 @@ export const useCasesColumns = ({ render: (assignees: CaseUI['assignees']) => ( ), + width: '10%', }, tags: { field: casesColumnsConfig.tags.field, @@ -193,7 +194,7 @@ export const useCasesColumns = ({ totalAlerts != null ? renderStringField(`${totalAlerts}`, `case-table-column-alertsCount`) : getEmptyCellValue(), - width: !isSelectorView ? '80px' : '55px', + width: !isSelectorView ? '70px' : '55px', }, totalComment: { field: casesColumnsConfig.totalComment.field, @@ -203,7 +204,7 @@ export const useCasesColumns = ({ totalComment != null ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) : getEmptyCellValue(), - width: '90px', + width: '75px', }, category: { field: casesColumnsConfig.category.field, @@ -217,7 +218,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: '120px', + width: '12%', }, closedAt: { field: casesColumnsConfig.closedAt.field, @@ -233,6 +234,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '10%', }, createdAt: { field: casesColumnsConfig.createdAt.field, @@ -248,6 +250,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '15%', }, updatedAt: { field: casesColumnsConfig.updatedAt.field, @@ -263,6 +266,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '15%', }, externalIncident: { // no field @@ -273,6 +277,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '10%', }, status: { field: casesColumnsConfig.status.field, @@ -285,7 +290,7 @@ export const useCasesColumns = ({ return getEmptyCellValue(); }, - width: '110px', + width: '100px', }, severity: { field: casesColumnsConfig.severity.field, @@ -326,6 +331,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '70px', }, }), [assignCaseAction, casesColumnsConfig, connectors, isSelectorView, userProfiles] diff --git a/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx index 914993648e29a..9b92baa30bb79 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx @@ -47,11 +47,14 @@ describe('Tags', () => { }; beforeEach(() => { - jest.clearAllMocks(); useGetTagsMock.mockReturnValue({ data: ['test'] }); appMockRender = createAppMockRenderer(); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('it renders', async () => { appMockRender.render( diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx index fe2deb74dfa10..7366acf6e051f 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx @@ -15,6 +15,7 @@ import type { CaseUI } from '../../../../common'; import { CaseViewAlerts } from './case_view_alerts'; import * as api from '../../../containers/api'; import type { FeatureIdsResponse } from '../../../containers/types'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; jest.mock('../../../containers/api'); @@ -54,7 +55,7 @@ describe('CaseUI View Page activity tab', () => { expect(getAlertsStateTableMock).toHaveBeenCalledWith({ alertsTableConfigurationRegistry: expect.anything(), configurationId: 'securitySolution-case', - featureIds: ['siem'], + ruleTypeIds: SECURITY_SOLUTION_RULE_TYPE_IDS, id: 'case-details-alerts-securitySolution', query: { ids: { @@ -88,7 +89,8 @@ describe('CaseUI View Page activity tab', () => { expect(getAlertsStateTableMock).toHaveBeenCalledWith({ alertsTableConfigurationRegistry: expect.anything(), configurationId: 'case-details-alerts-observability', - featureIds: ['observability'], + ruleTypeIds: ['log-threshold'], + consumers: ['observability'], id: 'case-details-alerts-observability', query: { ids: { diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx index 9570bee46b3fe..6f8223b5305f1 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx @@ -8,8 +8,8 @@ import React, { useMemo } from 'react'; import { EuiFlexItem, EuiFlexGroup, EuiProgress } from '@elastic/eui'; -import type { ValidFeatureId } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import { SECURITY_SOLUTION_OWNER } from '../../../../common/constants'; import type { CaseUI } from '../../../../common'; import { useKibana } from '../../../common/lib/kibana'; @@ -49,14 +49,16 @@ export const CaseViewAlerts = ({ caseData, onAlertsTableLoaded }: CaseViewAlerts ) : ''; - const alertStateProps = useMemo( + const alertStateProps: AlertsTableStateProps = useMemo( () => ({ alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry, configurationId: configId, id: `case-details-alerts-${caseData.owner}`, - featureIds: (caseData.owner === SECURITY_SOLUTION_OWNER - ? [AlertConsumers.SIEM] - : alertData?.featureIds ?? []) as ValidFeatureId[], + ruleTypeIds: + caseData.owner === SECURITY_SOLUTION_OWNER + ? SECURITY_SOLUTION_RULE_TYPE_IDS + : alertData?.ruleTypeIds ?? [], + consumers: alertData?.featureIds, query: alertIdsQuery, showAlertStatusWithFlapping: caseData.owner !== SECURITY_SOLUTION_OWNER, onLoaded: onAlertsTableLoaded, @@ -65,6 +67,7 @@ export const CaseViewAlerts = ({ caseData, onAlertsTableLoaded }: CaseViewAlerts triggersActionsUi.alertsTableConfigurationRegistry, configId, caseData.owner, + alertData?.ruleTypeIds, alertData?.featureIds, alertIdsQuery, onAlertsTableLoaded, diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx index 2a8a515df01ee..17bbcbfa045e4 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx @@ -12,7 +12,8 @@ import { FormTestComponent } from '../../../common/test_utils'; import { Create } from './create'; import { customFieldsConfigurationMock } from '../../../containers/mock'; -describe('Create ', () => { +// FLAKY: https://github.com/elastic/kibana/issues/202115 +describe.skip('Create ', () => { const onSubmit = jest.fn(); beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx index 9fabf39db0bc4..e77e8313c6963 100644 --- a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx +++ b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx @@ -8,7 +8,6 @@ import React, { memo, useCallback, useEffect, useMemo } from 'react'; import type { ActionParamsProps } from '@kbn/triggers-actions-ui-plugin/public/types'; -import type { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiCheckbox, @@ -37,7 +36,7 @@ const DEFAULT_EMPTY_TEMPLATE_KEY = 'defaultEmptyTemplateKey'; export const CasesParamsFieldsComponent: React.FunctionComponent< ActionParamsProps -> = ({ actionParams, editAction, errors, index, producerId, featureId }) => { +> = ({ actionParams, editAction, errors, index, producerId, featureId, ruleTypeId }) => { const { cloud, data: { dataViews: dataViewsService }, @@ -58,9 +57,7 @@ export const CasesParamsFieldsComponent: React.FunctionComponent< http, toasts, dataViewsService, - featureIds: producerId - ? [producerId as Exclude] - : [], + ruleTypeIds: ruleTypeId ? [ruleTypeId] : [], }); const { data: configurations, isLoading: isLoadingCaseConfiguration } = diff --git a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx index d09ebc9d747a7..d2874ad20246b 100644 --- a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx @@ -31,7 +31,8 @@ const defaultProps = { jest.mock('../../common/lib/kibana'); -describe(`UserActionsList`, () => { +// FLAKY: https://github.com/elastic/kibana/issues/176524 +describe.skip(`UserActionsList`, () => { let appMockRender: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cases/server/connectors/cases/index.test.ts b/x-pack/plugins/cases/server/connectors/cases/index.test.ts index 7b6d244d165b3..c0480d694184f 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.test.ts @@ -366,7 +366,7 @@ describe('getCasesConnectorType', () => { expect( adapter.getKibanaPrivileges?.({ - consumer: 'alerting', + consumer: 'not-exist', producer: AlertConsumers.LOGS, }) ).toEqual([ @@ -387,7 +387,7 @@ describe('getCasesConnectorType', () => { expect( adapter.getKibanaPrivileges?.({ - consumer: 'alerting', + consumer: 'alerts', producer: AlertConsumers.LOGS, }) ).toEqual([ diff --git a/x-pack/plugins/cases/server/connectors/cases/index.ts b/x-pack/plugins/cases/server/connectors/cases/index.ts index 07b4ab5e29551..b630de5209e2d 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.ts @@ -95,7 +95,7 @@ export const getCasesConnectorAdapter = ({ return { connectorTypeId: CASES_CONNECTOR_ID, ruleActionParamsSchema: CasesConnectorRuleActionParamsSchema, - buildActionParams: ({ alerts, rule, params, spaceId, ruleUrl }) => { + buildActionParams: ({ alerts, rule, params, ruleUrl }) => { const caseAlerts = [...alerts.new.data, ...alerts.ongoing.data]; const owner = getOwnerFromRuleConsumerProducer({ diff --git a/x-pack/plugins/cases/server/connectors/index.ts b/x-pack/plugins/cases/server/connectors/index.ts index 0b0f201b46d42..56dcddfbee76a 100644 --- a/x-pack/plugins/cases/server/connectors/index.ts +++ b/x-pack/plugins/cases/server/connectors/index.ts @@ -9,7 +9,7 @@ import type { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/act import type { KibanaRequest } from '@kbn/core-http-server'; import type { CoreSetup, SavedObjectsClientContract } from '@kbn/core/server'; import { SECURITY_EXTENSION_ID } from '@kbn/core/server'; -import type { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import type { CasesClient } from '../client'; import { getCasesConnectorAdapter, getCasesConnectorType } from './cases'; @@ -25,7 +25,7 @@ export function registerConnectorTypes({ isServerlessSecurity, }: { actions: ActionsPluginSetupContract; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; core: CoreSetup; getCasesClient: (request: KibanaRequest) => Promise; getSpaceId: (request?: KibanaRequest) => string; diff --git a/x-pack/plugins/cases/server/types.ts b/x-pack/plugins/cases/server/types.ts index a51817c9d7e58..8606808e1c183 100644 --- a/x-pack/plugins/cases/server/types.ts +++ b/x-pack/plugins/cases/server/types.ts @@ -29,7 +29,7 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { NotificationsPluginStart } from '@kbn/notifications-plugin/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; -import type { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { CasesClient } from './client'; import type { AttachmentFramework } from './attachment_framework/types'; @@ -37,7 +37,7 @@ import type { ExternalReferenceAttachmentTypeRegistry } from './attachment_frame import type { PersistableStateAttachmentTypeRegistry } from './attachment_framework/persistable_state_registry'; export interface CasesServerSetupDependencies { - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; actions: ActionsPluginSetup; lens: LensServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index 48ca36a02b2be..2a77cb0e7b5a1 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -74,6 +74,7 @@ "@kbn/core-logging-server-mocks", "@kbn/core-logging-browser-mocks", "@kbn/presentation-publishing", + "@kbn/securitysolution-rules", "@kbn/alerts-ui-shared", "@kbn/cloud-plugin", "@kbn/core-http-server-mocks", diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index ff4f51fc0b47a..6c1761dd1a314 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -16,8 +16,6 @@ import { CLOUDBEAT_AZURE, CLOUDBEAT_VULN_MGMT_AWS, VULN_MGMT_POLICY_TEMPLATE, - CLOUDBEAT_VULN_MGMT_GCP, - CLOUDBEAT_VULN_MGMT_AZURE, CLOUDBEAT_AKS, CLOUDBEAT_GKE, } from '../../common/constants'; @@ -158,30 +156,6 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { icon: 'logoAWS', benchmark: 'N/A', // TODO: change benchmark to be optional }, - { - type: CLOUDBEAT_VULN_MGMT_GCP, - name: i18n.translate('xpack.csp.vulnMgmtIntegration.gcpOption.nameTitle', { - defaultMessage: 'GCP', - }), - disabled: true, - icon: googleCloudLogo, - tooltip: i18n.translate('xpack.csp.vulnMgmtIntegration.gcpOption.tooltipContent', { - defaultMessage: 'Coming soon', - }), - benchmark: 'N/A', // TODO: change benchmark to be optional - }, - { - type: CLOUDBEAT_VULN_MGMT_AZURE, - name: i18n.translate('xpack.csp.vulnMgmtIntegration.azureOption.nameTitle', { - defaultMessage: 'Azure', - }), - disabled: true, - icon: 'logoAzure', - tooltip: i18n.translate('xpack.csp.vulnMgmtIntegration.azureOption.tooltipContent', { - defaultMessage: 'Coming soon', - }), - benchmark: 'N/A', // TODO: change benchmark to be optional - }, ], }, }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 9d8deb5b9892d..8d6f7292928e9 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -915,12 +915,16 @@ export const CspPolicyTemplateForm = memo {/* Defines the single enabled input of the active policy template */} - - + {input.type === 'cloudbeat/vuln_mgmt_aws' ? null : ( + <> + + + + )} {/* AWS account type selection box */} {input.type === 'cloudbeat/cis_aws' && ( @@ -954,8 +958,11 @@ export const CspPolicyTemplateForm = memo )} - {/* Defines the name/description */} - + {input.type === 'cloudbeat/vuln_mgmt_aws' ? null : ( + <> + + + )} updatePolicy({ ...newPolicy, [field]: value })} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx index 786f5526f496f..c479b3250fb7c 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx @@ -157,8 +157,16 @@ export const PolicyTemplateInfo = ({ postureType }: PolicyTemplateInfoProps) => {chunks}, + }} + /> + + )} diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts index b72cb27088eda..52a7c8b555094 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts @@ -31,7 +31,7 @@ import { bulkActionBenchmarkRulesHandler } from './v1'; // ... (additional benchmark rules) ]; } - + Response: { updated_benchmark_rules: CspBenchmarkRulesStates; Benchmark rules object that were affected @@ -67,7 +67,7 @@ export const defineBulkActionCspBenchmarkRulesRoute = (router: CspRouter) => const benchmarkRulesToUpdate = requestBody.rules; - const detectionRulesClient = (await context.alerting).getRulesClient(); + const detectionRulesClient = await (await context.alerting).getRulesClient(); const handlerResponse = await bulkActionBenchmarkRulesHandler( cspContext.soClient, diff --git a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx index 462cbbbd9288b..5f710c445471e 100644 --- a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx +++ b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx @@ -74,7 +74,10 @@ export function DatasetQualityDetailsContextProvider({ urlStateStorageContainer, datasetQualityDetailsState: state, }); - const breadcrumbValue = getBreadcrumbValue(state.dataStream, state.integration); + const breadcrumbValue = getBreadcrumbValue( + state.dataStream, + state.integration?.integration + ); setBreadcrumbs([{ text: breadcrumbValue }]); } ); diff --git a/x-pack/plugins/data_usage/common/rest_types/data_streams.ts b/x-pack/plugins/data_usage/common/rest_types/data_streams.ts index 87af7e29eccb6..17fc5fa5de053 100644 --- a/x-pack/plugins/data_usage/common/rest_types/data_streams.ts +++ b/x-pack/plugins/data_usage/common/rest_types/data_streams.ts @@ -7,6 +7,14 @@ import { schema, TypeOf } from '@kbn/config-schema'; +export const DataStreamsRequestSchema = { + query: schema.object({ + includeZeroStorage: schema.boolean({ defaultValue: false }), + }), +}; + +export type DataStreamsRequestQuery = TypeOf; + export const DataStreamsResponseSchema = { body: () => schema.arrayOf( diff --git a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts index ccc8158ecace7..07130c84b6fdf 100644 --- a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts +++ b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts @@ -39,6 +39,18 @@ export const METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP = Object.freeze>({ + 'Data Retained in Storage': 'storage_retained', + 'Data Ingested': 'ingest_rate', + 'Search VCU': 'search_vcu', + 'Ingest VCU': 'ingest_vcu', + 'ML VCU': 'ml_vcu', + 'Index Latency': 'index_latency', + 'Index Rate': 'index_rate', + 'Search Latency': 'search_latency', + 'Search Rate': 'search_rate', +}); + // type guard for MetricTypes export const isMetricType = (type: string): type is MetricTypes => METRIC_TYPE_VALUES.includes(type as MetricTypes); diff --git a/x-pack/plugins/data_usage/common/test_utils/index.ts b/x-pack/plugins/data_usage/common/test_utils/index.ts index c3c8e75b29454..4e13a4048ee2c 100644 --- a/x-pack/plugins/data_usage/common/test_utils/index.ts +++ b/x-pack/plugins/data_usage/common/test_utils/index.ts @@ -7,4 +7,3 @@ export { TestProvider } from './test_provider'; export { dataUsageTestQueryClientOptions } from './test_query_client_options'; -export { timeXMinutesAgo } from './time_ago'; diff --git a/x-pack/plugins/data_usage/common/utils.test.ts b/x-pack/plugins/data_usage/common/utils.test.ts new file mode 100644 index 0000000000000..fc6b158c1caa0 --- /dev/null +++ b/x-pack/plugins/data_usage/common/utils.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isDateRangeValid } from './utils'; + +describe('isDateRangeValid', () => { + describe('Valid ranges', () => { + it.each([ + ['both start and end date is `now`', { start: 'now', end: 'now' }], + ['start date is `now-10s` and end date is `now`', { start: 'now-10s', end: 'now' }], + ['bounded within the min and max date range', { start: 'now-8d', end: 'now-4s' }], + ])('should return true if %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(true); + }); + }); + + describe('Invalid ranges', () => { + it.each([ + ['starts before the min date', { start: 'now-11d', end: 'now-5s' }], + ['ends after the max date', { start: 'now-9d', end: 'now+2s' }], + [ + 'end date is before the start date even when both are within min and max date range', + { start: 'now-3s', end: 'now-10s' }, + ], + ])('should return false if the date range %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/data_usage/common/utils.ts b/x-pack/plugins/data_usage/common/utils.ts index ddd707b1134fd..3fd7240153d4d 100644 --- a/x-pack/plugins/data_usage/common/utils.ts +++ b/x-pack/plugins/data_usage/common/utils.ts @@ -6,5 +6,50 @@ */ import dateMath from '@kbn/datemath'; -export const dateParser = (date: string) => dateMath.parse(date)?.toISOString(); + +export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ + autoRefreshOptions: { + enabled: false, + duration: 10000, + }, + startDate: 'now-24h/h', + endDate: 'now', + maxDate: 'now+1s', + minDate: 'now-9d', + recentlyUsedDateRanges: [], +}); + export const momentDateParser = (date: string) => dateMath.parse(date); +export const transformToUTCtime = ({ + start, + end, + isISOString = false, +}: { + start: string; + end: string; + isISOString?: boolean; +}) => { + const utcOffset = momentDateParser(start)?.utcOffset() ?? 0; + const utcStart = momentDateParser(start)?.utc().add(utcOffset, 'm'); + const utcEnd = momentDateParser(end)?.utc().add(utcOffset, 'm'); + return { + start: isISOString ? utcStart?.toISOString() : momentDateParser(start), + end: isISOString ? utcEnd?.toISOString() : momentDateParser(end), + }; +}; + +export const isDateRangeValid = ({ start, end }: { start: string; end: string }): boolean => { + const startDate = momentDateParser(start); + const endDate = momentDateParser(end); + + if (!startDate || !endDate) { + return false; + } + const minDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.minDate); + const maxDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.maxDate); + return ( + startDate.isSameOrAfter(minDate, 's') && + endDate.isSameOrBefore(maxDate, 's') && + startDate <= endDate + ); +}; diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx index 91e2fd5ddafa9..befae95393e1c 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx @@ -344,18 +344,27 @@ describe('DataUsageMetrics', () => { }); it('should refetch usage metrics with `Refresh` button click', async () => { - const refetch = jest.fn(); - mockUseGetDataUsageMetrics.mockReturnValue({ - ...getBaseMockedDataUsageMetrics, - data: ['.ds-1', '.ds-2'], - isFetched: true, + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: generateDataStreams(3), + isFetching: false, }); + const refetch = jest.fn(); mockUseGetDataUsageMetrics.mockReturnValue({ ...getBaseMockedDataUsageMetrics, - isFetched: true, + data: {}, + isFetched: false, refetch, }); - const { getByTestId } = renderComponent(); + const { getByTestId, getAllByTestId } = renderComponent(); + + const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); + + expect(toggleFilterButton).toHaveTextContent('Data streams3'); + await user.click(toggleFilterButton); + const allFilterOptions = getAllByTestId('dataStreams-filter-option'); + await user.click(allFilterOptions[2]); + const refreshButton = getByTestId(`${testIdFilter}-super-refresh-button`); // click refresh 5 times for (let i = 0; i < 5; i++) { @@ -364,7 +373,7 @@ describe('DataUsageMetrics', () => { expect(mockUseGetDataUsageMetrics).toHaveBeenLastCalledWith( expect.any(Object), - expect.objectContaining({ enabled: false }) + expect.objectContaining({ enabled: true }) ); expect(refetch).toHaveBeenCalledTimes(5); }); diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx index d7d6417cf1444..efaa779dfe3c9 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx @@ -17,7 +17,12 @@ import { PLUGIN_NAME } from '../../translations'; import { useGetDataUsageMetrics } from '../../hooks/use_get_usage_metrics'; import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams'; import { useDataUsageMetricsUrlParams } from '../hooks/use_charts_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS, useDateRangePicker } from '../hooks/use_date_picker'; +import { + DEFAULT_DATE_RANGE_OPTIONS, + transformToUTCtime, + isDateRangeValid, +} from '../../../common/utils'; +import { useDateRangePicker } from '../hooks/use_date_picker'; import { ChartFilters, ChartFiltersProps } from './filters/charts_filters'; import { ChartsLoading } from './charts_loading'; import { NoDataCallout } from './no_data_callout'; @@ -104,11 +109,39 @@ export const DataUsageMetrics = memo( ...prevState, metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes, dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams, + from: startDateFromUrl ?? prevState.from, + to: endDateFromUrl ?? prevState.to, })); - }, [metricTypesFromUrl, dataStreamsFromUrl]); + }, [metricTypesFromUrl, dataStreamsFromUrl, startDateFromUrl, endDateFromUrl]); const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); + const isValidDateRange = useMemo( + () => + isDateRangeValid({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + }), + [dateRangePickerState.endDate, dateRangePickerState.startDate] + ); + + const enableFetchUsageMetricsData = useMemo( + () => + isValidDateRange && + metricsFilters.dataStreams.length > 0 && + metricsFilters.metricTypes.length > 0, + [isValidDateRange, metricsFilters.dataStreams, metricsFilters.metricTypes] + ); + + const utcTimeRange = useMemo( + () => + transformToUTCtime({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + isISOString: true, + }), + [dateRangePickerState] + ); const { error: errorFetchingDataUsageMetrics, data: usageMetricsData, @@ -118,12 +151,12 @@ export const DataUsageMetrics = memo( } = useGetDataUsageMetrics( { ...metricsFilters, - from: dateRangePickerState.startDate, - to: dateRangePickerState.endDate, + from: utcTimeRange.start as string, + to: utcTimeRange.end as string, }, { retry: false, - enabled: !!(metricsFilters.dataStreams.length && metricsFilters.metricTypes.length), + enabled: enableFetchUsageMetricsData, } ); @@ -134,8 +167,11 @@ export const DataUsageMetrics = memo( }, [isFetching, hasFetchedDataUsageMetricsData]); const onRefresh = useCallback(() => { + if (!enableFetchUsageMetricsData) { + return; + } refetchDataUsageMetrics(); - }, [refetchDataUsageMetrics]); + }, [enableFetchUsageMetricsData, refetchDataUsageMetrics]); const onChangeDataStreamsFilter = useCallback( (selectedDataStreams: string[]) => { @@ -206,6 +242,7 @@ export const DataUsageMetrics = memo( ( if (isMetricsFilter) { setUrlMetricTypesFilter( optionsToSelect - .map((option) => findKey(METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP, option)) + .map((option) => METRIC_TYPE_UI_OPTIONS_VALUES_TO_API_MAP[option]) .join(',') ); } diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx index 3b2142e0e3360..52561aa9f26f0 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx @@ -20,6 +20,7 @@ import { FilterName } from '../../hooks'; export interface ChartFiltersProps { dateRangePickerState: DateRangePickerValues; isDataLoading: boolean; + isUpdateDisabled: boolean; filterOptions: Record; onRefresh: () => void; onRefreshChange: (evt: OnRefreshChangeProps) => void; @@ -33,6 +34,7 @@ export const ChartFilters = memo( ({ dateRangePickerState, isDataLoading, + isUpdateDisabled, filterOptions, onClick, onRefresh, @@ -59,7 +61,8 @@ export const ChartFilters = memo( const onClickRefreshButton = useCallback(() => onClick(), [onClick]); return ( - + + {filters} @@ -78,6 +81,7 @@ export const ChartFilters = memo( data-test-subj={getTestId('super-refresh-button')} fill={false} isLoading={isDataLoading} + isDisabled={isUpdateDisabled} onClick={onClickRefreshButton} /> diff --git a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx index 81ab435670f89..1b04587b4245d 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx @@ -15,9 +15,8 @@ import type { OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; -import { momentDateParser } from '../../../../common/utils'; +import { momentDateParser, DEFAULT_DATE_RANGE_OPTIONS } from '../../../../common/utils'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; -import { DEFAULT_DATE_RANGE_OPTIONS } from '../../hooks/use_date_picker'; export interface DateRangePickerValues { autoRefreshOptions: { diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx index 3a1ba7dc1de62..37e1fdc5d1ab1 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx @@ -8,7 +8,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { type MetricTypes, isMetricType } from '../../../common/rest_types'; import { useUrlParams } from '../../hooks/use_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS } from './use_date_picker'; +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; interface UrlParamsDataUsageMetricsFilters { metricTypes: string; diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx index f4d198461f733..6b7e6f792b69b 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx @@ -12,18 +12,7 @@ import type { } from '@elastic/eui/src/components/date_picker/types'; import { useDataUsageMetricsUrlParams } from './use_charts_url_params'; import { DateRangePickerValues } from '../components/filters/date_picker'; - -export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ - autoRefreshOptions: { - enabled: false, - duration: 10000, - }, - startDate: 'now-24h/h', - endDate: 'now', - maxDate: 'now+1s', - minDate: 'now-9d', - recentlyUsedDateRanges: [], -}); +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; export const useDateRangePicker = () => { const { diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx index 5e224e635dca4..28be186a03805 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx +++ b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx @@ -7,7 +7,7 @@ import React, { ReactNode } from 'react'; import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGetDataUsageDataStreams } from './use_get_data_streams'; import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../common'; import { coreMock as mockCore } from '@kbn/core/public/mocks'; diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx index 1ddb84d89ffc9..a507c67207599 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx @@ -7,11 +7,12 @@ import React, { ReactNode } from 'react'; import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGetDataUsageMetrics } from './use_get_usage_metrics'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; import { coreMock as mockCore } from '@kbn/core/public/mocks'; -import { dataUsageTestQueryClientOptions, timeXMinutesAgo } from '../../common/test_utils'; +import { dataUsageTestQueryClientOptions } from '../../common/test_utils'; +import { transformToUTCtime } from '../../common/utils'; const useQueryMock = _useQuery as jest.Mock; @@ -40,16 +41,31 @@ jest.mock('../utils/use_kibana', () => { }; }); -const defaultUsageMetricsRequestBody = { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), - metricTypes: ['ingest_rate'], - dataStreams: ['ds-1'], -}; - describe('useGetDataUsageMetrics', () => { + const timeRange = { + start: 'now-15m', + end: 'now', + }; + const getUtcTimeRange = (range: { start: string; end: string }) => + transformToUTCtime({ + ...range, + isISOString: true, + }); + let defaultUsageMetricsRequestBody = { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: ['ds-1'], + }; + beforeEach(() => { jest.clearAllMocks(); + + defaultUsageMetricsRequestBody = { + ...defaultUsageMetricsRequestBody, + from: getUtcTimeRange(timeRange).start as string, + to: getUtcTimeRange(timeRange).end as string, + }; }); it('should call the correct API', async () => { @@ -67,6 +83,19 @@ describe('useGetDataUsageMetrics', () => { }); }); + it('should not call the API if invalid date range', async () => { + const requestBody = { + ...defaultUsageMetricsRequestBody, + from: 'invalid-date', + to: 'invalid-date', + }; + await renderHook(() => useGetDataUsageMetrics(requestBody, { enabled: true }), { + wrapper: createWrapper(), + }); + + expect(mockServices.http.post).not.toHaveBeenCalled(); + }); + it('should not call the API if disabled', async () => { await renderHook( () => useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { enabled: false }), diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts index da5f3004d0024..649bcb45ee376 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts @@ -8,7 +8,7 @@ import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { dateParser } from '../../common/utils'; +import { momentDateParser } from '../../common/utils'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; import type { UsageMetricsRequestBody, @@ -27,9 +27,15 @@ export const useGetDataUsageMetrics = ( ): UseQueryResult> => { const { http } = useKibanaContextForPlugin().services; + // parse values anyway to ensure they are valid + // and to avoid sending invalid values to the server + const from = momentDateParser(body.from)?.toISOString(); + const to = momentDateParser(body.to)?.toISOString(); + return useQuery>({ queryKey: ['get-data-usage-metrics', body], ...options, + enabled: !!(from && to) && options.enabled, keepPreviousData: true, queryFn: async ({ signal }) => { return http @@ -37,8 +43,8 @@ export const useGetDataUsageMetrics = ( signal, version: '1', body: JSON.stringify({ - from: dateParser(body.from), - to: dateParser(body.to), + from, + to, metricTypes: body.metricTypes, dataStreams: body.dataStreams, }), diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts index bfa236aa1cec0..6a1a4517bf6ef 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DataStreamsResponseSchema } from '../../../common/rest_types'; +import { DataStreamsResponseSchema, DataStreamsRequestSchema } from '../../../common/rest_types'; import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../../common'; import { DataUsageContext, DataUsageRouter } from '../../types'; import { getDataStreamsHandler } from './data_streams_handler'; @@ -23,7 +23,7 @@ export const registerDataStreamsRoute = ( { version: '1', validate: { - request: {}, + request: DataStreamsRequestSchema, response: { 200: DataStreamsResponseSchema, }, diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts index 99b4e982c5a40..726aa157050f8 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts @@ -9,12 +9,15 @@ import { RequestHandler } from '@kbn/core/server'; import { DataUsageContext, DataUsageRequestHandlerContext } from '../../types'; import { errorHandler } from '../error_handler'; import { getMeteringStats } from '../../utils/get_metering_stats'; +import { DataStreamsRequestQuery } from '../../../common/rest_types/data_streams'; export const getDataStreamsHandler = ( dataUsageContext: DataUsageContext -): RequestHandler => { +): RequestHandler => { const logger = dataUsageContext.logFactory.get('dataStreamsRoute'); - return async (context, _, response) => { + return async (context, request, response) => { + const { includeZeroStorage } = request.query; + logger.debug('Retrieving user data streams'); try { @@ -28,7 +31,7 @@ export const getDataStreamsHandler = ( ? meteringStats .sort((a, b) => b.size_in_bytes - a.size_in_bytes) .reduce>((acc, stat) => { - if (stat.size_in_bytes > 0) { + if (includeZeroStorage || stat.size_in_bytes > 0) { acc.push({ name: stat.name, storageSizeBytes: stat.size_in_bytes ?? 0, diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts index c0eb0e5e8ef2d..f2bccd6d9c6b0 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts @@ -19,7 +19,16 @@ import { DATA_USAGE_METRICS_API_ROUTE } from '../../../common'; import { createMockedDataUsageContext } from '../../mocks'; import { CustomHttpRequestError } from '../../utils'; import { AutoOpsError } from '../../services/errors'; -import { timeXMinutesAgo } from '../../../common/test_utils'; +import { transformToUTCtime } from '../../../common/utils'; + +const timeRange = { + start: 'now-15m', + end: 'now', +}; +const utcTimeRange = transformToUTCtime({ + ...timeRange, + isISOString: true, +}); describe('registerUsageMetricsRoute', () => { let mockCore: MockedKeys>; @@ -56,8 +65,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: [], }, @@ -123,8 +132,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate', 'storage_retained'], dataStreams: ['.ds-1', '.ds-2'], }, @@ -191,8 +200,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: ['.ds-1', '.ds-2'], }, diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts index c2dee4ca2ce52..eb27c2a9b7ede 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts @@ -7,6 +7,7 @@ import { chunk } from 'lodash/fp'; import { RequestHandler } from '@kbn/core/server'; +import { momentDateParser } from '../../../common/utils'; import type { MetricTypes, UsageMetricsAutoOpsResponseSchemaBody, @@ -37,6 +38,17 @@ export const getUsageMetricsHandler = ( logger.debug(`Retrieving usage metrics`); const { from, to, metricTypes, dataStreams: requestDsNames } = request.body; + // parse date strings to validate + const parsedFrom = momentDateParser(from)?.toISOString(); + const parsedTo = momentDateParser(to)?.toISOString(); + + if (!parsedFrom || !parsedTo) { + const customErrorMessage = `[request body.${ + !parsedTo ? 'to' : 'from' + }] Invalid date range ${!parsedTo ? to : from} is out of range`; + return errorHandler(logger, response, new CustomHttpRequestError(customErrorMessage, 400)); + } + // redundant check as we don't allow making requests via UI without data streams, // but it's here to make sure the request body is validated before requesting metrics from auto-ops if (!requestDsNames?.length) { @@ -74,8 +86,8 @@ export const getUsageMetricsHandler = ( const dataUsageService = new DataUsageService(logger); const metrics = await dataUsageService.getMetrics({ - from, - to, + from: parsedFrom, + to: parsedTo, metricTypes: formatStringParams(metricTypes) as MetricTypes[], dataStreams: formatStringParams(dataStreamsResponse.map((ds) => ds.name)), }); diff --git a/x-pack/plugins/data_usage/server/services/autoops_api.ts b/x-pack/plugins/data_usage/server/services/autoops_api.ts index 2ff824e04f6dd..d98b0c507fe14 100644 --- a/x-pack/plugins/data_usage/server/services/autoops_api.ts +++ b/x-pack/plugins/data_usage/server/services/autoops_api.ts @@ -14,12 +14,12 @@ import { Logger } from '@kbn/logging'; import type { AxiosError, AxiosRequestConfig } from 'axios'; import axios from 'axios'; import { LogMeta } from '@kbn/core/server'; +import { momentDateParser } from '../../common/utils'; import { UsageMetricsAutoOpsResponseSchema, type UsageMetricsAutoOpsResponseSchemaBody, type UsageMetricsRequestBody, } from '../../common/rest_types'; -import { dateParser } from '../../common/utils'; import { AutoOpsConfig } from '../types'; import { AutoOpsError } from './errors'; import { appContextService } from './app_context'; @@ -76,8 +76,8 @@ export class AutoOpsAPIService { const requestConfig: AxiosRequestConfig = { url: getAutoOpsAPIRequestUrl(autoopsConfig.api?.url, cloudSetup?.serverless.projectId), data: { - from: dateParser(requestBody.from), - to: dateParser(requestBody.to), + from: momentDateParser(requestBody.from)?.toISOString(), + to: momentDateParser(requestBody.to)?.toISOString(), size: requestBody.dataStreams.length, level: 'datastream', metric_types: requestBody.metricTypes, @@ -123,7 +123,7 @@ export class AutoOpsAPIService { `${AUTO_OPS_AGENT_CREATION_PREFIX} with an error ${error} ${requestConfigDebugStatus}`, errorMetadataWithRequestConfig ); - throw new Error(withRequestIdMessage(error.message)); + throw new AutoOpsError(withRequestIdMessage(error.message)); } const errorLogCodeCause = `${error.code} ${this.convertCauseErrorsToString(error)}`; @@ -152,14 +152,16 @@ export class AutoOpsAPIService { `${AUTO_OPS_AGENT_CREATION_PREFIX} while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`, errorMetadataWithRequestConfig ); - throw new Error(withRequestIdMessage(`no response received from the AutoOps API`)); + throw new AutoOpsError(withRequestIdMessage(`no response received from the AutoOps API`)); } else { // Something happened in setting up the request that triggered an Error this.logger.error( - `${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`, + `${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus} ${error.toJSON()}`, errorMetadataWithRequestConfig ); - throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR)); + throw new AutoOpsError( + withRequestIdMessage(`${AGENT_CREATION_FAILED_ERROR}, ${error.message}`) + ); } } ); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/README.md b/x-pack/plugins/discover_enhanced/ui_tests/README.md index 8320e9464d9ca..e6c5943e1533f 100644 --- a/x-pack/plugins/discover_enhanced/ui_tests/README.md +++ b/x-pack/plugins/discover_enhanced/ui_tests/README.md @@ -11,7 +11,10 @@ node scripts/scout_start_servers.js --serverless=es Then you can run the tests multiple times in another terminal with: ```bash -npx playwright test --config x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts +// ESS +npx playwright test --config x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts --grep @ess +// Serverless +npx playwright test --config x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts --grep @svlSearch // @svlOblt, @svlSecurity ``` Test results are available in `x-pack/plugins/discover_enhanced/ui_tests/output` diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts new file mode 100644 index 0000000000000..6ccbe4df990cb --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const QUERY_BAR_VALIDATION = { + SUGGESTIONS_COUNT: 'The query bar suggestions count should be', +}; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts new file mode 100644 index 0000000000000..3ac2c34586f4d --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const LOGSTASH_DEFAULT_START_TIME = '2015-09-19T06:31:44.000Z'; +export const LOGSTASH_DEFAULT_END_TIME = '2015-09-23T18:31:44.000Z'; + +export const DATA_VIEW_ID = { + ECOMMERCE: '5193f870-d861-11e9-a311-0fa548c5f953', + LOGSTASH: 'logstash-*', +}; + +export const DATA_VIEW = { + ECOMMERCE: 'ecommerce', + LOGSTASH: 'logstash-*', +}; + +export const LOGSTASH_OUT_OF_RANGE_DATES = { + from: 'Mar 1, 2020 @ 00:00:00.000', + to: 'Nov 1, 2020 @ 00:00:00.000', +}; + +export const LOGSTASH_IN_RANGE_DATES = { + from: 'Sep 19, 2015 @ 06:31:44.000', + to: 'Sep 23, 2015 @ 18:31:44.000', +}; + +export const ES_ARCHIVES = { + LOGSTASH: 'x-pack/test/functional/es_archives/logstash_functional', + NO_TIME_FIELD: 'test/functional/fixtures/es_archiver/index_pattern_without_timefield', + ECOMMERCE: 'x-pack/test/functional/es_archives/reporting/ecommerce', +}; + +export const KBN_ARCHIVES = { + INVALID_SCRIPTED_FIELD: 'test/functional/fixtures/kbn_archiver/invalid_scripted_field', + NO_TIME_FIELD: 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield', + DASHBOARD_DRILLDOWNS: + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns', + DISCOVER: 'test/functional/fixtures/kbn_archiver/discover', + ECOMMERCE: 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json', +}; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts index 38d4905f82e6f..cf12a98368b90 100644 --- a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts @@ -14,14 +14,23 @@ import { } from '@kbn/scout'; import { DemoPage } from './page_objects'; -interface ExtendedScoutTestFixtures extends ScoutTestFixtures { +export interface ExtendedScoutTestFixtures extends ScoutTestFixtures { pageObjects: PageObjects & { demo: DemoPage; }; } export const test = base.extend({ - pageObjects: async ({ pageObjects, page }, use) => { + pageObjects: async ( + { + pageObjects, + page, + }: { + pageObjects: ExtendedScoutTestFixtures['pageObjects']; + page: ExtendedScoutTestFixtures['page']; + }, + use: (pageObjects: ExtendedScoutTestFixtures['pageObjects']) => Promise + ) => { const extendedPageObjects = { ...pageObjects, demo: createLazyPageObject(DemoPage, page), @@ -30,3 +39,6 @@ export const test = base.extend( await use(extendedPageObjects); }, }); + +export * as testData from './constants'; +export * as assertionMessages from './assertion_messages'; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.ts new file mode 100644 index 0000000000000..914558fbdc97f --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.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 { expect } from '@kbn/scout'; +import { test, testData } from '../fixtures'; + +test.describe('Discover app - errors', { tag: ['@ess'] }, () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await kbnClient.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.INVALID_SCRIPTED_FIELD); + await uiSettings.setDefaultTime({ + from: testData.LOGSTASH_DEFAULT_START_TIME, + to: testData.LOGSTASH_DEFAULT_END_TIME, + }); + }); + + test.afterAll(async ({ kbnClient }) => { + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('should render invalid scripted field error', async ({ page }) => { + await page.testSubj.locator('discoverErrorCalloutTitle').waitFor({ state: 'visible' }); + await expect( + page.testSubj.locator('painlessStackTrace'), + 'Painless error stacktrace should be displayed' + ).toBeVisible(); + }); +}); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts new file mode 100644 index 0000000000000..7103f2b25e633 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ScoutWorkerFixtures, expect } from '@kbn/scout'; +import { test, testData } from '../fixtures'; + +const createSavedSearch = async ( + kbnClient: ScoutWorkerFixtures['kbnClient'], + searchId: string, + searchTitle: string, + dataViewId: string +) => + await kbnClient.savedObjects.create({ + type: 'search', + id: searchId, + overwrite: false, + attributes: { + title: searchTitle, + description: '', + columns: ['agent', 'bytes', 'clientip'], + sort: [['@timestamp', 'desc']], + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"highlightAll":true,"version":true,"query":{"language":"lucene","query":""},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + }, + }, + references: [ + { + id: dataViewId, + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + }, + ], + }); + +test.describe( + 'Discover app - saved search embeddable', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + const SAVED_SEARCH_TITLE = 'TempSearch'; + const SAVED_SEARCH_ID = '90943e30-9a47-11e8-b64d-95841ca0b247'; + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsPrivilegedUser(); + await pageObjects.dashboard.goto(); + }); + + test('should allow removing the dashboard panel after the underlying saved search has been deleted', async ({ + kbnClient, + page, + pageObjects, + }) => { + await pageObjects.dashboard.openNewDashboard(); + await createSavedSearch( + kbnClient, + SAVED_SEARCH_ID, + SAVED_SEARCH_TITLE, + testData.DATA_VIEW_ID.LOGSTASH + ); + await pageObjects.dashboard.addPanelFromLibrary(SAVED_SEARCH_TITLE); + await page.testSubj.locator('savedSearchTotalDocuments').waitFor({ + state: 'visible', + }); + + await pageObjects.dashboard.saveDashboard('Dashboard with deleted saved search'); + await kbnClient.savedObjects.delete({ + type: 'search', + id: SAVED_SEARCH_ID, + }); + + await page.reload(); + await page.waitForLoadingIndicatorHidden(); + await expect( + page.testSubj.locator('embeddableError'), + 'Embeddable error should be displayed' + ).toBeVisible(); + + await pageObjects.dashboard.removePanel('embeddableError'); + await expect( + page.testSubj.locator('embeddableError'), + 'Embeddable error should not be displayed' + ).toBeHidden(); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts new file mode 100644 index 0000000000000..1398f5f24ab27 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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/scout'; +import { test, testData } from '../fixtures'; +import type { ExtendedScoutTestFixtures } from '../fixtures'; + +const assertNoFilterAndEmptyQuery = async ( + filterBadge: { field: string; value: string }, + pageObjects: ExtendedScoutTestFixtures['pageObjects'], + page: ExtendedScoutTestFixtures['page'] +) => { + expect( + // checking if filter exists, enabled or disabled + await pageObjects.filterBar.hasFilter(filterBadge), + `Filter ${JSON.stringify(filterBadge)} should not exist` + ).toBe(false); + await expect( + page.testSubj.locator('queryInput'), + 'Query Bar input field should be empty' + ).toHaveText(''); +}; + +const assertDataViewIsSelected = async (page: ExtendedScoutTestFixtures['page'], name: string) => + await expect( + page.testSubj.locator('*dataView-switch-link'), + 'Incorrect data view is selected' + ).toHaveText(name); + +test.describe( + 'Discover app - saved searches', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + const START_TIME = '2019-04-27T23:56:51.374Z'; + const END_TIME = '2019-08-23T16:18:51.821Z'; + const PANEL_NAME = 'Ecommerce Data'; + const SEARCH_QUERY = 'customer_gender:MALE'; + const SAVED_SEARCH_NAME = 'test-unselect-saved-search'; + const filterFieldAndValue = { + field: 'category', + value: `Men's Shoes`, + }; + + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.ECOMMERCE); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DISCOVER); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.ECOMMERCE); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.ECOMMERCE, + 'timepicker:timeDefaults': `{ "from": "${START_TIME}", "to": "${END_TIME}"}`, + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth }) => { + await browserAuth.loginAsPrivilegedUser(); + }); + + test('should customize time range on dashboards', async ({ pageObjects, page }) => { + await pageObjects.dashboard.goto(); + await pageObjects.dashboard.openNewDashboard(); + await pageObjects.dashboard.addPanelFromLibrary(PANEL_NAME); + await page.testSubj.locator('savedSearchTotalDocuments').waitFor({ + state: 'visible', + }); + + await pageObjects.dashboard.customizePanel({ + name: PANEL_NAME, + customTimeRageCommonlyUsed: { value: 'Last_90 days' }, + }); + await expect( + page.testSubj.locator('embeddedSavedSearchDocTable').locator('.euiDataGrid__noResults'), + 'No results message in Saved Search panel should be visible' + ).toBeVisible(); + }); + + test(`should unselect saved search when navigating to a 'new'`, async ({ + pageObjects, + page, + }) => { + await pageObjects.discover.goto(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + await pageObjects.filterBar.addFilter({ + ...filterFieldAndValue, + operator: 'is', + }); + await page.testSubj.fill('queryInput', SEARCH_QUERY); + await page.testSubj.click('querySubmitButton'); + await pageObjects.discover.waitForHistogramRendered(); + + await pageObjects.discover.saveSearch(SAVED_SEARCH_NAME); + await pageObjects.discover.waitForHistogramRendered(); + + expect( + await pageObjects.filterBar.hasFilter({ + ...filterFieldAndValue, + enabled: true, // Filter is enabled by default + }) + ).toBe(true); + await expect(page.testSubj.locator('queryInput')).toHaveText(SEARCH_QUERY); + + // create new search + await pageObjects.discover.clickNewSearch(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // change data view + await pageObjects.discover.selectDataView(testData.DATA_VIEW.LOGSTASH); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // change data view again + await pageObjects.discover.selectDataView(testData.DATA_VIEW.ECOMMERCE); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // create new search again + await pageObjects.discover.clickNewSearch(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts index ff1389e85924e..04836afb99b5b 100644 --- a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts @@ -6,51 +6,54 @@ */ import { expect } from '@kbn/scout'; -import { test } from '../fixtures'; +import { test, testData, assertionMessages } from '../fixtures'; -test.describe('Discover app - value suggestions', () => { - test.beforeAll(async ({ esArchiver, kbnClient }) => { - await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await kbnClient.importExport.load( - 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' - ); - await kbnClient.uiSettings.update({ - defaultIndex: 'logstash-*', // TODO: investigate why it is required for `node scripts/playwright_test.js` run - 'doc_table:legacy': false, +test.describe( + 'Discover app - value suggestions: useTimeRange enabled', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); }); - }); - test.afterAll(async ({ kbnClient }) => { - await kbnClient.uiSettings.unset('doc_table:legacy'); - await kbnClient.uiSettings.unset('defaultIndex'); - await kbnClient.savedObjects.cleanStandardList(); - }); + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); - test.beforeEach(async ({ browserAuth, pageObjects }) => { - await browserAuth.loginAsPrivilegedUser(); - await pageObjects.discover.goto(); - }); + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); - test('dont show up if outside of range', async ({ page, pageObjects }) => { - await pageObjects.datePicker.setAbsoluteRange({ - from: 'Mar 1, 2020 @ 00:00:00.000', - to: 'Nov 1, 2020 @ 00:00:00.000', + test('dont show up if outside of range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_OUT_OF_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect(page.testSubj.locator('autoCompleteSuggestionText')).toHaveCount(0); }); - await page.testSubj.fill('queryInput', 'extension.raw : '); - await expect(page.testSubj.locator('autoCompleteSuggestionText')).toHaveCount(0); - }); + test('show up if in range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); - test('show up if in range', async ({ page, pageObjects }) => { - await pageObjects.datePicker.setAbsoluteRange({ - from: 'Sep 19, 2015 @ 06:31:44.000', - to: 'Sep 23, 2015 @ 18:31:44.000', + test('also displays descriptions for operators', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw'); + await expect(page.testSubj.locator('^autocompleteSuggestion-operator')).toHaveCount(2); }); - await page.testSubj.fill('queryInput', 'extension.raw : '); - await expect(page.testSubj.locator('autoCompleteSuggestionText')).toHaveCount(5); - const actualSuggestions = await page.testSubj - .locator('autoCompleteSuggestionText') - .allTextContents(); - expect(actualSuggestions.join(',')).toContain('jpg'); - }); -}); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts index 4ba9450869313..319d8af3e93c9 100644 --- a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts @@ -6,39 +6,42 @@ */ import { expect } from '@kbn/scout'; -import { test } from '../fixtures'; +import { test, testData, assertionMessages } from '../fixtures'; -test.describe('Discover app - value suggestions non-time based', () => { - test.beforeAll(async ({ esArchiver, kbnClient }) => { - await esArchiver.loadIfNeeded( - 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' - ); - await kbnClient.importExport.load( - 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' - ); - await kbnClient.uiSettings.update({ - defaultIndex: 'without-timefield', - 'doc_table:legacy': false, +test.describe( + 'Discover app - value suggestions non-time based', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.NO_TIME_FIELD); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.NO_TIME_FIELD); + await uiSettings.set({ + defaultIndex: 'without-timefield', + }); }); - }); - test.afterAll(async ({ kbnClient }) => { - await kbnClient.uiSettings.unset('doc_table:legacy'); - await kbnClient.uiSettings.unset('defaultIndex'); - await kbnClient.savedObjects.cleanStandardList(); - }); + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex'); + await kbnClient.savedObjects.cleanStandardList(); + }); - test.beforeEach(async ({ browserAuth, pageObjects }) => { - await browserAuth.loginAsPrivilegedUser(); - await pageObjects.discover.goto(); - }); + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); - test('shows all auto-suggest options for a filter in discover context app', async ({ page }) => { - await page.testSubj.fill('queryInput', 'type.keyword : '); - await expect(page.testSubj.locator('autoCompleteSuggestionText')).toHaveCount(1); - const actualSuggestions = await page.testSubj - .locator('autoCompleteSuggestionText') - .allTextContents(); - expect(actualSuggestions.join(',')).toContain('"apache"'); - }); -}); + test('shows all auto-suggest options for a filter in discover context app', async ({ + page, + }) => { + await page.testSubj.fill('queryInput', 'type.keyword : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(1); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('"apache"'); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts new file mode 100644 index 0000000000000..857709b091940 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData, assertionMessages } from '../fixtures'; + +test.describe( + 'Discover app - value suggestions: useTimeRange disabled', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + 'autocomplete:useTimeRange': false, + }); + }); + + test.afterAll(async ({ uiSettings, kbnClient }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await uiSettings.set({ 'autocomplete:useTimeRange': true }); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('show up if outside of range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_OUT_OF_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); + + test('show up if in range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); + } +); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts index 57b7745a89c78..2a4ad628eb757 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts @@ -9,6 +9,9 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import { DeleteByQueryRequest } from '@elastic/elasticsearch/lib/api/types'; +import { i18n } from '@kbn/i18n'; +import { getResourceName } from '.'; import { knowledgeBaseIngestPipeline } from '../ai_assistant_data_clients/knowledge_base/ingest_pipeline'; import { GetElser } from '../types'; @@ -96,3 +99,45 @@ export const deletePipeline = async ({ esClient, id }: DeletePipelineParams): Pr return response.acknowledged; }; + +export const removeLegacyQuickPrompt = async (esClient: ElasticsearchClient) => { + try { + const deleteQuery: DeleteByQueryRequest = { + index: `${getResourceName('prompts')}-*`, + query: { + bool: { + must: [ + { + term: { + name: ESQL_QUERY_GENERATION_TITLE, + }, + }, + { + term: { + prompt_type: 'quick', + }, + }, + { + term: { + is_default: true, + }, + }, + ], + }, + }, + }; + return esClient.deleteByQuery(deleteQuery); + } catch (e) { + // swallow any errors + return { + total: 0, + }; + } +}; + +const ESQL_QUERY_GENERATION_TITLE = i18n.translate( + 'xpack.elasticAssistantPlugin.assistant.quickPrompts.esqlQueryGenerationTitle', + { + defaultMessage: 'ES|QL Query Generation', + } +); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts index 81ddd69fb67d3..233b5781ddf68 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts @@ -40,7 +40,7 @@ import { hasAIAssistantLicense } from '../routes/helpers'; const TOTAL_FIELDS_LIMIT = 2500; -function getResourceName(resource: string) { +export function getResourceName(resource: string) { return `.kibana-elastic-ai-assistant-${resource}`; } diff --git a/x-pack/plugins/elastic_assistant/server/plugin.ts b/x-pack/plugins/elastic_assistant/server/plugin.ts index 4386b95c3fa7a..110dbbc05f2a6 100755 --- a/x-pack/plugins/elastic_assistant/server/plugin.ts +++ b/x-pack/plugins/elastic_assistant/server/plugin.ts @@ -25,7 +25,7 @@ import { RequestContextFactory } from './routes/request_context_factory'; import { PLUGIN_ID } from '../common/constants'; import { registerRoutes } from './routes/register_routes'; import { appContextService } from './services/app_context'; -import { createGetElserId } from './ai_assistant_service/helpers'; +import { createGetElserId, removeLegacyQuickPrompt } from './ai_assistant_service/helpers'; export class ElasticAssistantPlugin implements @@ -109,6 +109,12 @@ export class ElasticAssistantPlugin this.getElserId = createGetElserId(this.mlTrainedModelsProvider); } }); + removeLegacyQuickPrompt(core.elasticsearch.client.asInternalUser) + .then((res) => { + if (res?.total) + this.logger.info(`Removed ${res.total} legacy quick prompts from AI Assistant`); + }) + .catch(() => {}); return { actions: plugins.actions, diff --git a/x-pack/plugins/embeddable_enhanced/kibana.jsonc b/x-pack/plugins/embeddable_enhanced/kibana.jsonc index d795afa4d7938..3b9632d4bf36c 100644 --- a/x-pack/plugins/embeddable_enhanced/kibana.jsonc +++ b/x-pack/plugins/embeddable_enhanced/kibana.jsonc @@ -5,7 +5,7 @@ "@elastic/kibana-presentation" ], "group": "platform", - "visibility": "private", + "visibility": "shared", "description": "Extends embeddable plugin with more functionality", "plugin": { "id": "embeddableEnhanced", diff --git a/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx index 2920a4900f0bd..bcb4441750d08 100644 --- a/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AISearchGuide } from './components/ai_search_guide/ai_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchAISearch: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - - ); - } - - return ; - }; - +export const EnterpriseSearchAISearch: React.FC = () => { return ( - {showView()} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx index d3261eb265c06..a9914ca244f5b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx @@ -14,8 +14,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { AnalyticsOverview } from './components/analytics_overview/analytics_overview'; import { Analytics } from '.'; @@ -30,10 +28,4 @@ describe('EnterpriseSearchAnalytics', () => { expect(wrapper.find(AnalyticsOverview)).toHaveLength(1); }); - - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow(); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx index 19d7b67be6bfc..03de5eff97837 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx @@ -9,30 +9,18 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AnalyticsCollectionView } from './components/analytics_collection_view/analytics_collection_view'; import { AnalyticsOverview } from './components/analytics_overview/analytics_overview'; import { ROOT_PATH, COLLECTION_VIEW_PATH } from './routes'; -export const Analytics: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const Analytics: React.FC = () => { return ( - {incompatibleVersions ? ( - - ) : ( - - )} + diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx index 299a840cf8919..779158ae1e114 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx @@ -20,6 +20,7 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, + useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -44,6 +45,7 @@ export const CustomizationModal: React.FC = ({ sortFields, }) => { const { engine } = useValues(EngineLogic); + const modalTitleId = useGeneratedHtmlId(); const [selectedFilterFields, setSelectedFilterFields] = useState( filterFields.map(fieldNameToComboBoxOption) @@ -69,9 +71,9 @@ export const CustomizationModal: React.FC = ({ ); return ( - + - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.title', { @@ -132,8 +134,11 @@ export const CustomizationModal: React.FC = ({ - {CANCEL_BUTTON_LABEL} + + {CANCEL_BUTTON_LABEL} + { onSave({ diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd4..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 2d1235e0b5c46..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => { - return ( - <> - - - - - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index bd8d6c30a0188..2c73e7606cd86 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -16,7 +16,6 @@ import { Redirect } from 'react-router-dom'; import { shallow, ShallowWrapper } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { rerender } from '../test_helpers'; jest.mock('./app_logic', () => ({ AppLogic: jest.fn() })); @@ -26,7 +25,6 @@ import { Credentials } from './components/credentials'; import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; -import { ErrorConnecting } from './components/error_connecting'; import { Library } from './components/library'; import { MetaEngineCreation } from './components/meta_engine_creation'; import { RoleMappings } from './components/role_mappings'; @@ -42,12 +40,6 @@ describe('AppSearch', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); }); - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow(); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders AppSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(); @@ -55,14 +47,6 @@ describe('AppSearch', () => { expect(wrapper.find(AppSearchUnconfigured)).toHaveLength(1); }); - it('renders ErrorConnecting when Enterprise Search is unavailable', () => { - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - const wrapper = shallow(); - - const errorConnection = wrapper.find(ErrorConnecting); - expect(errorConnection).toHaveLength(1); - }); - it('renders AppSearchConfigured when config.host is set & available', () => { setMockValues({ errorConnectingMessage: '', config: { host: 'some.url' } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 7f7237555867b..1a75cd58b1a24 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -12,19 +12,15 @@ import { useValues } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; import { EndpointsHeaderAction } from '../shared/layout/endpoints_header_action'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { Credentials } from './components/credentials'; import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; -import { ErrorConnecting } from './components/error_connecting'; import { KibanaHeaderActions } from './components/layout'; import { Library } from './components/library'; import { MetaEngineCreation } from './components/meta_engine_creation'; @@ -47,24 +43,10 @@ import { export const AppSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - const showView = () => { if (!config.host) { return ; - } else if (incompatibleVersions) { - return ( - - ); - } else if (errorConnectingMessage) { - return ; } - return )} />; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx index f3047ac23b645..99f44cbb01f0c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx @@ -21,7 +21,6 @@ import { } from '../../../routes'; import { EnterpriseSearchApplicationsPageTemplate } from '../../layout/page_template'; -import { SearchApplicationError } from '../search_application_error'; import { SearchApplicationViewLogic } from '../search_application_view_logic'; import { SearchApplicationAPI } from './search_application_api'; @@ -47,7 +46,6 @@ const DOCUMENTATION_TAB_TITLE = i18n.translate( defaultMessage: 'Documentation', } ); -const ConnectTabs: string[] = Object.values(SearchApplicationConnectTabs); const getTabBreadCrumb = (tabId: string) => { switch (tabId) { case SearchApplicationConnectTabs.SEARCHAPI: @@ -76,26 +74,6 @@ export const SearchApplicationConnect: React.FC = () => { ); }; - if (!ConnectTabs.includes(connectTabId)) { - return ( - - - - ); - } - return ( { } }; -const ContentTabs: string[] = Object.values(SearchApplicationContentTabs); - export const SearchApplicationContent = () => { const { searchApplicationName, isLoadingSearchApplication, hasSchemaConflicts } = useValues( SearchApplicationViewLogic @@ -74,26 +71,6 @@ export const SearchApplicationContent = () => { contentTabId?: string; }>(); - if (!ContentTabs.includes(contentTabId)) { - return ( - - - - ); - } - const onTabClick = (tab: SearchApplicationContentTabs) => () => { KibanaLogic.values.navigateToUrl( generateEncodedPath(SEARCH_APPLICATION_CONTENT_PATH, { diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx deleted file mode 100644 index d24675822a730..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx +++ /dev/null @@ -1,68 +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 { setMockValues } from '../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { HttpError } from '../../../../../common/types/api'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { NotFoundPrompt } from '../../../shared/not_found'; -import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; - -import { mountWithIntl } from '../../../test_helpers'; - -import { SearchApplicationError } from './search_application_error'; - -describe('SearchApplicationError', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues({}); - }); - - it('renders 404 prompt for 404 error', () => { - const error = { - body: { - error: 'NOT_FOUND', - message: 'Not Found', - statusCode: 404, - }, - } as HttpError; - const wrapper = mountWithIntl(); - - expect(wrapper.find(NotFoundPrompt)).toHaveLength(1); - expect(wrapper.find(SendEnterpriseSearchTelemetry)).toHaveLength(1); - expect(wrapper.find(ErrorStatePrompt)).toHaveLength(0); - - const notFound = wrapper.find(NotFoundPrompt); - expect(notFound.prop('backToLink')).toEqual('/search_applications'); - expect(notFound.prop('backToContent')).toEqual('Back to Search Applications'); - - const telemetry = wrapper.find(SendEnterpriseSearchTelemetry); - expect(telemetry.prop('action')).toEqual('error'); - expect(telemetry.prop('metric')).toEqual('not_found'); - }); - - it('renders error prompt for api errors', () => { - const error = { - body: { - error: 'ERROR', - message: 'Internal Server Error', - statusCode: 500, - }, - } as HttpError; - const wrapper = mountWithIntl(); - - expect(wrapper.find(ErrorStatePrompt)).toHaveLength(1); - expect(wrapper.find(SendEnterpriseSearchTelemetry)).toHaveLength(1); - expect(wrapper.find(NotFoundPrompt)).toHaveLength(0); - - const telemetry = wrapper.find(SendEnterpriseSearchTelemetry); - expect(telemetry.prop('action')).toEqual('error'); - expect(telemetry.prop('metric')).toEqual('cannot_connect'); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx deleted file mode 100644 index 49a783dbbcec3..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { i18n } from '@kbn/i18n'; - -import { APPLICATIONS_PLUGIN } from '../../../../../common/constants'; -import { HttpError } from '../../../../../common/types/api'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { NotFoundPrompt } from '../../../shared/not_found'; -import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; - -import { SEARCH_APPLICATIONS_PATH } from '../../routes'; - -export const SearchApplicationError: React.FC<{ error?: HttpError; notFound?: boolean }> = ({ - error, - notFound, -}) => { - if (notFound || error?.body?.statusCode === 404) { - return ( - <> - - - - ); - } - return ( - <> - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx index fef6f95c3b435..001d36a0faf43 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx @@ -6,13 +6,12 @@ */ import React, { useEffect } from 'react'; -import { useParams, Redirect } from 'react-router-dom'; +import { Redirect } from 'react-router-dom'; import { useValues, useActions } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { Status } from '../../../../../common/types/api'; import { SEARCH_APPLICATION_PATH, SEARCH_APPLICATION_CONTENT_PATH, @@ -22,52 +21,23 @@ import { SearchApplicationContentTabs, } from '../../routes'; -import { EnterpriseSearchApplicationsPageTemplate } from '../layout/page_template'; import { DeleteSearchApplicationModal } from '../search_applications/delete_search_application_modal'; import { SearchApplicationConnect } from './connect/search_application_connect'; import { SearchApplicationDocsExplorer } from './docs_explorer/docs_explorer'; import { SearchApplicationContent } from './search_application_content'; -import { SearchApplicationError } from './search_application_error'; import { SearchApplicationViewLogic } from './search_application_view_logic'; export const SearchApplicationView: React.FC = () => { const { fetchSearchApplication, closeDeleteSearchApplicationModal } = useActions( SearchApplicationViewLogic ); - const { - searchApplicationName, - fetchSearchApplicationApiError, - fetchSearchApplicationApiStatus, - hasSchemaConflicts, - isDeleteModalVisible, - } = useValues(SearchApplicationViewLogic); - const { tabId = SearchApplicationViewTabs.DOCS_EXPLORER } = useParams<{ - tabId?: string; - }>(); + const { searchApplicationName, isDeleteModalVisible } = useValues(SearchApplicationViewLogic); useEffect(() => { fetchSearchApplication({ name: searchApplicationName }); }, [searchApplicationName]); - if (fetchSearchApplicationApiStatus === Status.ERROR) { - return ( - } - hasSchemaConflicts={hasSchemaConflicts} - /> - ); - } - return ( <> {isDeleteModalVisible ? ( @@ -92,22 +62,6 @@ export const SearchApplicationView: React.FC = () => { from={`${SEARCH_APPLICATION_PATH}/${SearchApplicationViewTabs.CONNECT}`} to={`${SEARCH_APPLICATION_PATH}/${SearchApplicationViewTabs.CONNECT}/${SearchApplicationConnectTabs.SEARCHAPI}`} /> - - - - - ); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx index 532ba053af1d0..78f20bc122ca8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx @@ -26,7 +26,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; -import { Status } from '../../../../../common/types/api'; import { EnterpriseSearchApplicationIndex } from '../../../../../common/types/search_applications'; @@ -35,8 +34,6 @@ import { healthColorsMap } from '../../../shared/constants/health_colors'; import { generateEncodedPath } from '../../../shared/encode_path_params'; import { EuiLinkTo } from '../../../shared/react_router_helpers'; -import { SearchApplicationError } from '../search_application/search_application_error'; - import { SearchApplicationIndicesFlyoutLogic } from './search_application_indices_flyout_logic'; export const SearchApplicationIndicesFlyout: React.FC = () => { @@ -45,15 +42,11 @@ export const SearchApplicationIndicesFlyout: React.FC = () => { searchApplicationName, isSearchApplicationLoading, isFlyoutVisible, - fetchSearchApplicationApiStatus, - fetchSearchApplicationApiError, } = useValues(SearchApplicationIndicesFlyoutLogic); const { closeFlyout } = useActions(SearchApplicationIndicesFlyoutLogic); if (!searchApplicationData) return null; const { indices } = searchApplicationData; - const searchApplicationFetchError = - fetchSearchApplicationApiStatus === Status.ERROR ? true : false; const columns: Array> = [ { @@ -139,11 +132,7 @@ export const SearchApplicationIndicesFlyout: React.FC = () => { - {searchApplicationFetchError ? ( - - ) : ( - - )} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx index e5da2b5610d3d..881f042d1d626 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ElasticsearchGuide } from './components/elasticsearch_guide/elasticsearch_guide'; import { ROOT_PATH } from './routes'; -export const Elasticsearch: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - - ); - } - - return ; - }; - +export const Elasticsearch: React.FC = () => { return ( - {showView()} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts index 8d2ee0ee87aa3..d2bd5cfe71493 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts @@ -10,6 +10,7 @@ import { HttpLogic } from '../../../shared/http'; export interface GenerateConnectorNamesApiArgs { connectorName?: string; connectorType?: string; + isManagedConnector?: boolean; } export interface GenerateConnectorNamesApiResponse { @@ -19,14 +20,16 @@ export interface GenerateConnectorNamesApiResponse { } export const generateConnectorNames = async ( - { connectorType, connectorName }: GenerateConnectorNamesApiArgs = { connectorType: 'custom' } + { connectorType, connectorName, isManagedConnector }: GenerateConnectorNamesApiArgs = { + connectorType: 'custom', + } ) => { if (connectorType === '') { connectorType = 'custom'; } const route = `/internal/enterprise_search/connectors/generate_connector_name`; return await HttpLogic.values.http.post(route, { - body: JSON.stringify({ connectorName, connectorType }), + body: JSON.stringify({ connectorName, connectorType, isManagedConnector }), }); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx index 5a2e279026bda..dbc854251e33a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx @@ -27,7 +27,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { Connector } from '@kbn/search-connectors'; +import { Connector, MANAGED_CONNECTOR_INDEX_PREFIX } from '@kbn/search-connectors'; import { Status } from '../../../../../common/types/api'; @@ -65,66 +65,114 @@ export const AttachIndexBox: React.FC = ({ connector }) => createApiError, attachApiError, } = useValues(AttachIndexLogic); + + const { makeRequest } = useActions(FetchAvailableIndicesAPILogic); + const { data, status } = useValues(FetchAvailableIndicesAPILogic); + const isLoading = [Status.IDLE, Status.LOADING].includes(status); + + // Helper function to remove the managed connector index prefix from the index name + const removePrefixConnectorIndex = (connectorIndexName: string) => { + if (!connector.is_native) { + return connectorIndexName; + } + if (connectorIndexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) { + return connectorIndexName.substring(MANAGED_CONNECTOR_INDEX_PREFIX.length); + } + return connectorIndexName; + }; + + // Helper function to add the managed connector index prefix to the index name + const prefixConnectorIndex = (connectorIndexName: string) => { + if (!connector.is_native) { + return connectorIndexName; + } + if (connectorIndexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) { + return connectorIndexName; + } + return `${MANAGED_CONNECTOR_INDEX_PREFIX}${connectorIndexName}`; + }; + + const [query, setQuery] = useState<{ + isFullMatch: boolean; + searchValue: string; + }>(); + const [sanitizedName, setSanitizedName] = useState( + prefixConnectorIndex(formatApiName(connector.name)) + ); + const [selectedIndex, setSelectedIndex] = useState< { label: string; shouldCreate?: boolean } | undefined >( + // For managed connectors, the index name should be displayed without prefix + // As `content-` is fixed UI element connector.index_name ? { - label: connector.index_name, + label: removePrefixConnectorIndex(connector.index_name), } : undefined ); - const [selectedLanguage] = useState(); - const [query, setQuery] = useState<{ - isFullMatch: boolean; - searchValue: string; - }>(); - const [sanitizedName, setSanitizedName] = useState(formatApiName(connector.name)); - - const { makeRequest } = useActions(FetchAvailableIndicesAPILogic); - const { data, status } = useValues(FetchAvailableIndicesAPILogic); - const isLoading = [Status.IDLE, Status.LOADING].includes(status); const onSave = () => { - if (selectedIndex?.shouldCreate) { - createIndex({ indexName: selectedIndex.label, language: selectedLanguage ?? null }); - } else if (selectedIndex && !(selectedIndex.label === connector.index_name)) { - attachIndex({ connectorId: connector.id, indexName: selectedIndex.label }); + if (!selectedIndex) return; + // Always attach and/or create prefixed index for managed connectors + const prefixedIndex = prefixConnectorIndex(selectedIndex.label); + if (selectedIndex.shouldCreate) { + createIndex({ + indexName: prefixedIndex, + language: null, + }); + } else if (connector.index_name !== prefixedIndex) { + attachIndex({ + connectorId: connector.id, + indexName: prefixedIndex, + }); } }; + // For managed connectors ensure that only prefixed indices are displayed in the dropdown + // This takes care of the initial component state where all indices could be displayed briefly const options: Array> = isLoading ? [] - : data?.indexNames.map((name) => { - return { + : data?.indexNames + .filter((name) => !connector.is_native || name.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) + .map((name) => ({ label: name, - }; - }) ?? []; + value: removePrefixConnectorIndex(name), + })) ?? []; const hasMatchingOptions = data?.indexNames.some((name) => - name.toLocaleLowerCase().includes(query?.searchValue.toLocaleLowerCase() ?? '') + name + .toLocaleLowerCase() + .includes(prefixConnectorIndex(query?.searchValue?.toLocaleLowerCase() || '')) ) ?? false; + const isFullMatch = data?.indexNames.some( - (name) => name.toLocaleLowerCase() === query?.searchValue.toLocaleLowerCase() + (name) => + name.toLocaleLowerCase() === + prefixConnectorIndex(query?.searchValue?.toLocaleLowerCase() || '') ) ?? false; - const shouldPrependUserInputAsOption = !!query?.searchValue && hasMatchingOptions && !isFullMatch; + const shouldPrependUserInputAsOption = + !!query && + !!query.searchValue && + query.searchValue !== MANAGED_CONNECTOR_INDEX_PREFIX && + hasMatchingOptions && + !isFullMatch; const groupedOptions: Array> = shouldPrependUserInputAsOption ? [ - ...[ - { - label: CREATE_NEW_INDEX_GROUP_LABEL, - options: [ - { - label: query.searchValue, - }, - ], - }, - ], - ...[{ label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }], + { + label: CREATE_NEW_INDEX_GROUP_LABEL, + options: [ + { + label: prefixConnectorIndex(query!.searchValue), + value: query!.searchValue, + }, + ], + }, + { label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }, ] : [{ label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }]; @@ -144,7 +192,8 @@ export const AttachIndexBox: React.FC = ({ connector }) => }, [query]); useEffect(() => { - setSanitizedName(formatApiName(connector.name)); + // Suggested name for managed connector should include the content- prefix + setSanitizedName(prefixConnectorIndex(formatApiName(connector.name))); }, [connector.name]); const { hash } = useLocation(); @@ -170,9 +219,10 @@ export const AttachIndexBox: React.FC = ({ connector }) => } ) : attachApiError?.body?.message || createApiError?.body?.message || undefined; + if (indexName) { - // We don't want to let people edit indices when on the index route - return <>; + // Do not render when on the index route + return null; } return ( @@ -189,8 +239,8 @@ export const AttachIndexBox: React.FC = ({ connector }) => @@ -201,10 +251,20 @@ export const AttachIndexBox: React.FC = ({ connector }) => 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexLabel', { defaultMessage: 'Associated index' } )} - helpText={i18n.translate( - 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexHelpTextLabel', - { defaultMessage: 'You can use an existing index or create a new one.' } - )} + helpText={ + connector.is_native + ? i18n.translate( + 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedManagedConnectorIndexHelpTextLabel', + { + defaultMessage: + 'Managed connector indices must be prefixed. Use an existing index or create a new one.', + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexHelpTextLabel', + { defaultMessage: 'You can use an existing index or create a new one.' } + ) + } error={error} isInvalid={!!error} > @@ -217,11 +277,13 @@ export const AttachIndexBox: React.FC = ({ connector }) => 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.indexSelector.customOption', { defaultMessage: 'Create index {searchValue}', - values: { searchValue: '{searchValue}' }, + values: { searchValue: prefixConnectorIndex('{searchValue}') }, } )} isLoading={isLoading} options={groupedOptions} + singleSelection={{ asPlainText: connector.is_native }} + prepend={connector.is_native ? MANAGED_CONNECTOR_INDEX_PREFIX : undefined} onKeyDown={(event) => { // Index name should not contain spaces if (event.key === ' ') { @@ -229,28 +291,34 @@ export const AttachIndexBox: React.FC = ({ connector }) => } }} onSearchChange={(searchValue) => { + // Match by option value to ensure accurate comparison with non-prefixed + // user input for managed connectors setQuery({ - isFullMatch: options.some((option) => option.label === searchValue), - searchValue, + isFullMatch: options.some( + (option) => option.value === prefixConnectorIndex(searchValue) + ), + searchValue: prefixConnectorIndex(searchValue), }); }} onChange={(selection) => { - const currentSelection = selection[0] ?? undefined; + const currentSelection = selection[0]; const selectedIndexOption = currentSelection ? { - label: currentSelection.label, + label: removePrefixConnectorIndex(currentSelection.label), shouldCreate: shouldPrependUserInputAsOption && - !!(currentSelection?.label === query?.searchValue), + currentSelection.value === query?.searchValue, } : undefined; setSelectedIndex(selectedIndexOption); }} selectedOptions={selectedIndex ? [selectedIndex] : undefined} onCreateOption={(value) => { - setSelectedIndex({ label: value.trim(), shouldCreate: true }); + setSelectedIndex({ + label: removePrefixConnectorIndex(value.trim()), + shouldCreate: true, + }); }} - singleSelection />
        @@ -261,8 +329,12 @@ export const AttachIndexBox: React.FC = ({ connector }) => onSave()} - disabled={!selectedIndex || selectedIndex.label === connector.index_name} + onClick={onSave} + disabled={ + !selectedIndex || + prefixConnectorIndex(selectedIndex.label) === connector.index_name || + !!error + } isLoading={isSaveLoading} > {i18n.translate('xpack.enterpriseSearch.attachIndexBox.saveConfigurationButtonLabel', { @@ -314,15 +386,13 @@ export const AttachIndexBox: React.FC = ({ connector }) => } )} - {indexExists[sanitizedName] ? ( + {indexExists[sanitizedName] && ( {i18n.translate('xpack.enterpriseSearch.attachIndexBox.indexNameExistsError', { defaultMessage: 'Index with name {indexName} already exists', values: { indexName: sanitizedName }, })} - ) : ( - <> )} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx index 29a54c913301a..86a3bf83f1b78 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx @@ -11,7 +11,6 @@ import { useValues } from 'kea'; import { EuiBadge, - EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIcon, @@ -23,12 +22,8 @@ import { import { i18n } from '@kbn/i18n'; import { BetaConnectorCallout } from '../../../shared/beta/beta_connector_callout'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; -import { GenerateConnectorApiKeyApiLogic } from '../../api/connector/generate_connector_api_key_api_logic'; - -import { ApiKeyConfig } from '../search_index/connector/api_key_configuration'; import { ConvertConnector } from '../search_index/connector/native_connector_configuration/convert_connector'; import { NativeConnectorConfigurationConfig } from '../search_index/connector/native_connector_configuration/native_connector_configuration_config'; import { ResearchConfiguration } from '../search_index/connector/native_connector_configuration/research_configuration'; @@ -39,9 +34,7 @@ import { ConnectorViewLogic } from './connector_view_logic'; export const NativeConnectorConfiguration: React.FC = () => { const { connector } = useValues(ConnectorViewLogic); - const { config, connectorTypes: connectors } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { data: apiKeyData } = useValues(GenerateConnectorApiKeyApiLogic); + const { connectorTypes: connectors } = useValues(KibanaLogic); const NATIVE_CONNECTORS = useMemo( () => connectors.filter(({ isNative }) => isNative), @@ -68,7 +61,6 @@ export const NativeConnectorConfiguration: React.FC = () => { }; const iconPath = nativeConnector.iconPath; - const hasApiKey = !!(connector.api_key_id ?? apiKeyData); // TODO service_type === "" is considered unknown/custom connector multipleplaces replace all of them with a better solution const isBeta = @@ -114,39 +106,8 @@ export const NativeConnectorConfiguration: React.FC = () => { - {config.host && config.canDeployEntSearch && errorConnectingMessage && ( - <> - -

        - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.text', - { - defaultMessage: - 'Elastic managed connectors require a running Enterprise Search instance.', - } - )} -

        -
        - - - - )} - { - <> - - - - } + + {connector.index_name && ( <> @@ -170,23 +131,6 @@ export const NativeConnectorConfiguration: React.FC = () => { - - -

        - {i18n.translate( - 'xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.apiKey.title', - { defaultMessage: 'API Key' } - )} -

        -
        - - -
        - diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx index 906c64ccae8e2..3fdd3d379eacb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx @@ -95,7 +95,7 @@ export const ConnectorDetailOverview: React.FC = () => { <> { = ({ isCrawler }) => { {productFeatures.hasDefaultIngestPipeline && showDefaultSettingsFlyout && ( setShowDefaultSettingsFlyout(false)} /> )} - {Boolean(errorConnectingMessage) && ( - <> - - - - )} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx index 9e0aed3fa75f0..f91a8eff670fe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx @@ -6,7 +6,10 @@ */ import React, { useState } from 'react'; +import { css } from '@emotion/react'; + import { + EuiButton, EuiButtonIcon, EuiCallOut, EuiFlexGroup, @@ -83,13 +86,15 @@ const connectorClientPopoverPanels = [ ]; export interface ConnectorDescriptionPopoverProps { - isDisabled: boolean; isNative: boolean; + isRunningLocally?: boolean; + showIsOnlySelfManaged: boolean; } export const ConnectorDescriptionPopover: React.FC = ({ isNative, - isDisabled, + isRunningLocally, + showIsOnlySelfManaged, }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const panels = isNative ? nativePopoverPanels : connectorClientPopoverPanels; @@ -111,55 +116,115 @@ export const ConnectorDescriptionPopover: React.FC - - {isDisabled && ( - - - + {(showIsOnlySelfManaged || isRunningLocally) && ( + <> + + + - + size="s" + iconType="warning" + color="warning" + /> + + + + + )} + + {!isRunningLocally && ( + + {panels.map((panel) => { + return ( + + + + + {panel.icons.map((icon, index) => ( + + {icon} + + ))} + + + + +

        {panel.description}

        +
        +
        +
        +
        + ); + })}
        )} - - - {panels.map((panel) => { - return ( - - + + + + +

        + {i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.learnMore', + { defaultMessage: 'Explore Elastic Cloud with your 14-day free trial' } + )} +

        +
        +
        + + + {i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.learnMore', + { + defaultMessage: + 'Take advantage of Elastic managed connectors and generative AI capabilities to address search challenges across your organization in real time, at scale.', + } + )} + + + + - - - {panel.icons.map((icon, index) => ( - - {icon} - - ))} - - - - -

        {panel.description}

        -
        -
        -
        + {i18n.translate('xpack.enterpriseSearch.createConnector.startTrialButtonLabel', { + defaultMessage: 'Start free trial', + })} +
        - ); - })} -
        + + + )}
        ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx index 6e83bf98c2371..095990c823f0a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx @@ -65,9 +65,14 @@ export const CreateConnector: React.FC = () => { const { setCurrentStep } = useActions(NewConnectorLogic); const stepStates = generateStepState(currentStep); + const { config } = useValues(KibanaLogic); + const isRunningLocally = (config.host ?? '').includes('localhost'); + useEffect(() => { - // TODO: separate this to ability and preference - if (selectedConnector && !selectedConnector.isNative && selfManagePreference === 'native') { + if ( + (selectedConnector && !selectedConnector.isNative && selfManagePreference === 'native') || + isRunningLocally + ) { setSelfManagePreference('selfManaged'); } }, [selectedConnector]); @@ -141,6 +146,7 @@ export const CreateConnector: React.FC = () => { setSelfManagePreference(preference); }} error={errorToText(error)} + isRunningLocally={isRunningLocally} /> ), }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx index 46840d577e4d6..fb740189148d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx @@ -41,6 +41,7 @@ import { SelfManagePreference } from './create_connector'; interface StartStepProps { error?: string | React.ReactNode; + isRunningLocally: boolean; onSelfManagePreferenceChange(preference: SelfManagePreference): void; selfManagePreference: SelfManagePreference; setCurrentStep: Function; @@ -49,6 +50,7 @@ interface StartStepProps { export const StartStep: React.FC = ({ title, + isRunningLocally, selfManagePreference, setCurrentStep, onSelfManagePreferenceChange, @@ -144,6 +146,7 @@ export const StartStep: React.FC = ({ generateConnectorName({ connectorName: rawName, connectorType: selectedConnector.serviceType, + isManagedConnector: selectedConnector.isNative, }); } }} @@ -208,14 +211,15 @@ export const StartStep: React.FC = ({ { defaultMessage: 'Elastic managed' } )} checked={selfManagePreference === 'native'} - disabled={selectedConnector?.isNative === false} + disabled={selectedConnector?.isNative === false || isRunningLocally} onChange={() => onSelfManagePreferenceChange('native')} name="setUp" /> @@ -233,7 +237,7 @@ export const StartStep: React.FC = ({ /> - + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd4..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 69f479026014e..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => { - return ( - <> - - - - - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts index 0c8a81d90149a..f2f327f40650e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts @@ -192,6 +192,7 @@ export const NewConnectorLogic = kea { )} - {Boolean(errorConnectingMessage) && ( - - - - )} { }} > - {errorConnectingMessage && productFeatures.hasWebCrawler && } - <> - - - {availableIngestionMethodOptions.map((type) => ( - - { - if (type === INGESTION_METHOD_IDS.CONNECTOR) { - KibanaLogic.values.navigateToUrl(NEW_INDEX_SELECT_CONNECTOR_PATH); - } else if (type === INGESTION_METHOD_IDS.CRAWLER) { - KibanaLogic.values.navigateToUrl(NEW_CRAWLER_PATH); - } else { - KibanaLogic.values.navigateToUrl(NEW_API_PATH); - } - }} - /> - - ))} - - - + + + {availableIngestionMethodOptions.map((type) => ( + + { + if (type === INGESTION_METHOD_IDS.CONNECTOR) { + KibanaLogic.values.navigateToUrl(NEW_INDEX_SELECT_CONNECTOR_PATH); + } else if (type === INGESTION_METHOD_IDS.CRAWLER) { + KibanaLogic.values.navigateToUrl(NEW_CRAWLER_PATH); + } else { + KibanaLogic.values.navigateToUrl(NEW_API_PATH); + } + }} + /> + + ))} + + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx deleted file mode 100644 index 3fa7b40117a68..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiCallOut, EuiSpacer, EuiText } from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; - -import { FormattedMessage } from '@kbn/i18n-react'; - -import { EuiLinkTo } from '../../../../shared/react_router_helpers'; - -import { ERROR_STATE_PATH } from '../../../routes'; - -export const CannotConnect: React.FC = () => { - return ( - - - - - {i18n.translate('xpack.enterpriseSearch.content.cannotConnect.body', { - defaultMessage: 'More information.', - })} - - ), - }} - /> - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx index 6cdd06f1586a2..e8876a7c56818 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx @@ -18,8 +18,6 @@ import { i18n } from '@kbn/i18n'; import { ClientConfigType } from '../../../../../common/types'; import { generateEncodedPath } from '../../../shared/encode_path_params'; -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; import { SEARCH_INDEX_PATH, SEARCH_INDEX_TAB_PATH } from '../../routes'; @@ -71,7 +69,6 @@ export const SearchIndex: React.FC = () => { }>(); const { indexName } = useValues(IndexNameLogic); - const { errorConnectingMessage } = useValues(HttpLogic); /** * Guided Onboarding needs us to mark the add data step as complete as soon as the user has data in an index. @@ -286,32 +283,19 @@ export const SearchIndex: React.FC = () => { }} > - + ); }; interface ContentProps { config?: ClientConfigType; - errorConnectingMessage: string; index?: ElasticsearchViewIndex; tabId?: string; tabs: EuiTabbedContentTab[]; } -const Content: React.FC = ({ - config, - errorConnectingMessage, - index, - tabs, - tabId, -}) => { +const Content: React.FC = ({ index, tabs, tabId }) => { const selectedTab = useMemo(() => tabs.find((tab) => tab.id === tabId), [tabId]); const onTabClick = (tab: EuiTabbedContentTab) => { @@ -329,9 +313,6 @@ const Content: React.FC = ({ if (isCrawlerIndex(index) && !index.connector) { return ; } - if (isCrawlerIndex(index) && (Boolean(errorConnectingMessage) || !config?.host)) { - return ; - } return ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx index dece1b4beb2f7..d44e95b6271e4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx @@ -11,10 +11,8 @@ import { useValues, useActions } from 'kea'; import { EuiButton, - EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiSpacer, EuiTitle, EuiSwitch, EuiSearchBar, @@ -26,14 +24,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { AddContentEmptyPrompt } from '../../../shared/add_content_empty_prompt'; -import { HttpLogic } from '../../../shared/http/http_logic'; import { KibanaLogic } from '../../../shared/kibana'; -import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { handlePageChange } from '../../../shared/table_pagination'; import { NEW_API_PATH } from '../../routes'; import { EnterpriseSearchContentPageTemplate } from '../layout/page_template'; -import { CannotConnect } from '../search_index/components/cannot_connect'; +// import { CannotConnect } from '../search_index/components/cannot_connect'; import { DefaultSettingsFlyout } from '../settings/default_settings_flyout'; import { DeleteIndexModal } from './delete_index_modal'; @@ -53,8 +50,7 @@ export const SearchIndices: React.FC = () => { const [showHiddenIndices, setShowHiddenIndices] = useState(false); const [onlyShowSearchOptimizedIndices, setOnlyShowSearchOptimizedIndices] = useState(false); const [searchQuery, setSearchValue] = useState(''); - const { config, productFeatures } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); + const { productFeatures } = useValues(KibanaLogic); const [showDefaultSettingsFlyout, setShowDefaultSettingsFlyout] = useState(false); useEffect(() => { @@ -142,37 +138,6 @@ export const SearchIndices: React.FC = () => { {productFeatures.hasDefaultIngestPipeline && showDefaultSettingsFlyout && ( setShowDefaultSettingsFlyout(false)} /> )} - {config.host && config.canDeployEntSearch && errorConnectingMessage && ( - <> - - - - )} - {!config.host && config.canDeployEntSearch && ( - <> - -

        - -

        - - - -
        - - - )} {!hasNoIndices ? ( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx index 9fcfe7c7fcfab..a32062256eec5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx @@ -15,7 +15,6 @@ import React from 'react'; import { shallow } from 'enzyme'; import { SetupGuide } from '../enterprise_search_overview/components/setup_guide'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SearchIndicesRouter } from './components/search_indices'; @@ -28,15 +27,6 @@ describe('EnterpriseSearchContent', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); }); - it('renders VersionMismatchPage when there are mismatching versions', () => { - setMockValues({ config: { canDeployEntSearch: true, host: 'host' } }); - const wrapper = shallow( - - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders EnterpriseSearchContentConfigured when config.host is set & available', () => { setMockValues({ config: { canDeployEntSearch: true, host: 'some.url' }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx index 2ec701aa9847b..d464923dea2ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx @@ -8,17 +8,10 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; -import { useValues } from 'kea'; - import { Route, Routes } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { SetupGuide } from '../enterprise_search_overview/components/setup_guide'; -import { ErrorStatePrompt } from '../shared/error_state'; -import { HttpLogic } from '../shared/http'; -import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ConnectorsRouter } from './components/connectors/connectors_router'; import { CrawlersRouter } from './components/connectors/crawlers_router'; @@ -27,44 +20,20 @@ import { SearchIndicesRouter } from './components/search_indices'; import { CONNECTORS_PATH, CRAWLERS_PATH, - ERROR_STATE_PATH, ROOT_PATH, SEARCH_INDICES_PATH, SETUP_GUIDE_PATH, } from './routes'; export const EnterpriseSearchContent: React.FC = (props) => { - const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (config.host && config.canDeployEntSearch && incompatibleVersions) { - return ( - - ); - } - - return )} />; - }; - return ( - - {config.host && config.canDeployEntSearch && errorConnectingMessage ? ( - - ) : ( - - )} + + )} /> - {showView()} ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd4..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 6fc4ae2842200..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => ( - - - - - -); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx index dd67bf33d987b..3718a495cd17b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx @@ -11,8 +11,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { ErrorStateCallout } from '../../../shared/error_state'; - import { TrialCallout } from '../trial_callout'; import { ElasticsearchProductCard } from './elasticsearch_product_card'; @@ -34,23 +32,6 @@ describe('ProductSelector', () => { expect(wrapper.find(TrialCallout)).toHaveLength(1); }); - it('does not render connection error callout without an error', () => { - setMockValues({ config: { canDeployEntSearch: true, host: 'localhost' } }); - const wrapper = shallow(); - - expect(wrapper.find(ErrorStateCallout)).toHaveLength(0); - }); - - it('does render connection error callout with an error', () => { - setMockValues({ - config: { canDeployEntSearch: true, host: 'localhost' }, - errorConnectingMessage: '502 Bad Gateway', - }); - const wrapper = shallow(); - - expect(wrapper.find(ErrorStateCallout)).toHaveLength(1); - }); - describe('access checks when host is set', () => { beforeEach(() => { setMockValues({ config: { canDeployEntSearch: true, host: 'localhost' } }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx index 1f25f5f69c2e0..7c22f5bfd433a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx @@ -20,8 +20,6 @@ import { import { i18n } from '@kbn/i18n'; import { ApiKeyPanel } from '../../../shared/api_key/api_key_panel'; -import { ErrorStateCallout } from '../../../shared/error_state'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; import { SetSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SearchLabsBanner } from '../../../shared/search_labs_banner/search_labs_banner'; @@ -39,11 +37,8 @@ import './product_selector.scss'; import { WelcomeBanner } from './welcome_banner'; export const ProductSelector: React.FC = () => { - const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); const { user } = useValues(KibanaLogic); - const showErrorConnecting = !!(config.host && errorConnectingMessage); // The create index flow does not work without ent-search, when content is updated // to no longer rely on ent-search we can always show the Add Content component @@ -80,12 +75,6 @@ export const ProductSelector: React.FC = () => { - {showErrorConnecting && ( - <> - - - - )} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx index 6742de0816f81..7754aa0cf11f7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx @@ -11,8 +11,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; @@ -29,17 +27,4 @@ describe('EnterpriseSearchOverview', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); expect(wrapper.find(ProductSelector)).toHaveLength(1); }); - - it('renders the version error message if versions mismatch and the host is configured', () => { - setMockValues({ - errorConnectingMessage: '', - config: { host: 'localhost' }, - }); - const wrapper = shallow( - - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - expect(wrapper.find(ProductSelector)).toHaveLength(0); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx index 64ab8e44a69ae..70d4b40bb7f90 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx @@ -7,49 +7,22 @@ import React from 'react'; -import { useValues } from 'kea'; - import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; import { ROOT_PATH, SETUP_GUIDE_PATH } from './routes'; -export const EnterpriseSearchOverview: React.FC = ({ - enterpriseSearchVersion, - kibanaVersion, -}) => { - const { config } = useValues(KibanaLogic); - - const incompatibleVersions = !!( - config.host && isVersionMismatch(enterpriseSearchVersion, kibanaVersion) - ); - - const showView = () => { - if (incompatibleVersions) { - return ( - - ); - } - - return ; - }; - +export const EnterpriseSearchOverview: React.FC = ({}) => { return ( - {showView()} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx b/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx index 118cb5cb7caf2..e41918d8ce29d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SearchExperiencesGuide } from './components/search_experiences_guide'; import { ROOT_PATH } from './routes'; -export const SearchExperiences: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - - ); - } - - return ; - }; - +export const SearchExperiences: React.FC = () => { return ( - {showView()} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx index f33142bae940c..e6e5e3e66bbf4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx @@ -12,29 +12,17 @@ import { Switch } from 'react-router-dom'; import { Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SemanticSearchGuide } from './components/semantic_search_guide/semantic_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchSemanticSearch: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const EnterpriseSearchSemanticSearch: React.FC = () => { return ( - {incompatibleVersions ? ( - - ) : ( - - )} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss deleted file mode 100644 index 0d9926ab147bf..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss +++ /dev/null @@ -1,12 +0,0 @@ -.troubleshootingSteps { - text-align: left; - - li { - margin: $euiSizeS auto; - } - - ul, - ol { - margin-bottom: 0; - } -} diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx deleted file mode 100644 index 867702b8326ab..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import '../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, mockKibanaValues } from '../../__mocks__/kea_logic'; - -import React from 'react'; - -import { mountWithIntl } from '../../test_helpers'; - -import { ErrorStatePrompt } from '.'; - -describe('ErrorState', () => { - const values = { - config: {}, - cloud: { isCloudEnabled: true }, - errorConnectingMessage: '502 Bad Gateway', - }; - - beforeAll(() => { - setMockValues(values); - }); - - it('renders an error message', () => { - const wrapper = mountWithIntl(); - expect(wrapper.text()).toContain('502 Bad Gateway'); - }); - - it('renders a cloud specific error on cloud deployments', () => { - setMockValues({ - ...values, - cloud: { isCloudEnabled: true }, - }); - const wrapper = mountWithIntl(); - - expect(wrapper.find('[data-test-subj="CloudError"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="SelfManagedError"]').exists()).toBe(false); - }); - - it('renders a different error if not a cloud deployment', () => { - setMockValues({ - ...values, - cloud: { isCloudEnabled: false }, - }); - const wrapper = mountWithIntl(); - - expect(wrapper.find('[data-test-subj="CloudError"]').exists()).toBe(false); - expect(wrapper.find('[data-test-subj="SelfManagedError"]').exists()).toBe(true); - }); - - describe('chrome visiblity', () => { - it('sets chrome visibility to true when not on personal dashboard route', () => { - mockKibanaValues.history.location.pathname = '/overview'; - mountWithIntl(); - - expect(mockKibanaValues.setChromeIsVisible).toHaveBeenCalledWith(true); - }); - - it('sets chrome visibility to false when on personal dashboard route', () => { - mockKibanaValues.history.location.pathname = '/p/sources'; - mountWithIntl(); - - expect(mockKibanaValues.setChromeIsVisible).toHaveBeenCalledWith(false); - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx deleted file mode 100644 index e744d8d9b1250..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect } from 'react'; - -import { useValues } from 'kea'; - -import { EuiEmptyPrompt, EuiCode, EuiLink, EuiCodeBlock, EuiCallOut } from '@elastic/eui'; -import { CloudSetup } from '@kbn/cloud-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { HttpLogic } from '../http'; -import { KibanaLogic } from '../kibana'; -import { EuiButtonTo } from '../react_router_helpers'; - -import './error_state_prompt.scss'; - -/** - * Personal dashboard urls begin with /p/ - * EX: http://localhost:5601/app/enterprise_search/workplace_search/p/sources - */ -const WORKPLACE_SEARCH_PERSONAL_DASHBOARD_PATH = '/p/'; - -export const ErrorStatePrompt: React.FC = () => { - const { setChromeIsVisible, history } = useValues(KibanaLogic); - const isWorkplaceSearchPersonalDashboardRoute = history.location.pathname.includes( - WORKPLACE_SEARCH_PERSONAL_DASHBOARD_PATH - ); - - useEffect(() => { - // We hide the Kibana chrome for Workplace Search for Personal Dashboard routes. It is reenabled when the user enters the - // Workplace Search organization admin section of the product. If the Enterprise Search API is not working, we never show - // the chrome and this can have adverse effects when the user leaves thispage and returns to Kibana. To get around this, - // we always show the chrome when the error state is shown, unless the user is visiting the Personal Dashboard. - setChromeIsVisible(!isWorkplaceSearchPersonalDashboardRoute); - }, []); - - return ( - - - - } - titleSize="l" - body={} - actions={[ - - - , - ]} - /> - ); -}; - -export const ErrorStateCallout: React.FC = () => { - return ( - - - - - - - ); -}; - -const ErrorBody: React.FC = () => { - const { errorConnectingMessage } = useValues(HttpLogic); - const { config, cloud } = useValues(KibanaLogic); - return ( - <> -

        - - {config.host} - - ), - }} - /> -

        - {errorConnectingMessage} - {cloud?.isCloudEnabled ? cloudError(cloud) : nonCloudError()} - - ); -}; - -const cloudError = (cloud: Partial) => { - const deploymentUrl = cloud?.deploymentUrl; - return ( -

        - - {i18n.translate( - 'xpack.enterpriseSearch.errorConnectingState.cloudErrorMessageLinkText', - { - defaultMessage: 'Check your deployment settings', - } - )} - - ), - }} - /> -

        - ); -}; - -const nonCloudError = () => { - return ( -
          -
        1. - config/kibana.yml, - }} - /> -
        2. -
        3. - -
        4. -
        5. - -
            -
          • - -
          • -
          -
        6. -
        - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx deleted file mode 100644 index f6d5ef4aa4212..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { mount } from 'enzyme'; - -import { VersionMismatchError } from './version_mismatch_error'; - -describe('VersionMismatchError', () => { - it('renders', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Enterprise Search version: 8.0.0'); - expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Kibana version: 8.1.0'); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx deleted file mode 100644 index 56915663961de..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -interface Props { - enterpriseSearchVersion?: string; - kibanaVersion?: string; -} - -export const VersionMismatchError: React.FC = ({ - enterpriseSearchVersion, - kibanaVersion, -}) => { - return ( - - {i18n.translate('xpack.enterpriseSearch.versionMismatch.title', { - defaultMessage: 'Incompatible version error', - })} - - } - titleSize="l" - body={ - <> - {i18n.translate('xpack.enterpriseSearch.versionMismatch.body', { - defaultMessage: - 'Your Kibana and Enterprise Search versions do not match. To access Enterprise Search, use the same major and minor version for each service.', - })} - -
        - {i18n.translate('xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText', { - defaultMessage: 'Enterprise Search version: {enterpriseSearchVersion}', - values: { enterpriseSearchVersion }, - })} -
        -
        - {i18n.translate('xpack.enterpriseSearch.versionMismatch.kibanaVersionText', { - defaultMessage: 'Kibana version: {kibanaVersion}', - values: { kibanaVersion }, - })} -
        - - } - /> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx deleted file mode 100644 index d86a1187bd4b9..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { VersionMismatchError } from './version_mismatch_error'; -import { VersionMismatchPage } from './version_mismatch_page'; - -describe('VersionMismatchPage', () => { - it('renders', () => { - const wrapper = shallow( - - ); - expect(wrapper.find(VersionMismatchError).exists()).toBe(true); - expect(wrapper.find(VersionMismatchError).props()).toEqual({ - kibanaVersion: '8.1.0', - enterpriseSearchVersion: '8.0.0', - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx deleted file mode 100644 index 0d730f9dee9ef..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { VersionMismatchError } from './version_mismatch_error'; - -interface Props { - enterpriseSearchVersion?: string; - kibanaVersion?: string; -} - -export const VersionMismatchPage: React.FC = (props) => ( - - - -); diff --git a/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx index ce678121253f0..2d85725dc552d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx @@ -12,29 +12,17 @@ import { Switch } from 'react-router-dom'; import { Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { VectorSearchGuide } from './components/vector_search_guide/vector_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchVectorSearch: React.FC = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const EnterpriseSearchVectorSearch: React.FC = () => { return ( - {incompatibleVersions ? ( - - ) : ( - - )} + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx index 6771168239126..67b7469fcfe36 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx @@ -15,12 +15,9 @@ import { Redirect } from 'react-router-dom'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { WorkplaceSearchHeaderActions } from './components/layout'; import { SourcesRouter } from './views/content_sources'; import { SourceAdded } from './views/content_sources/components/source_added'; -import { ErrorState } from './views/error_state'; import { NotFound } from './views/not_found'; import { Overview } from './views/overview'; import { RoleMappings } from './views/role_mappings'; @@ -34,14 +31,6 @@ import { } from '.'; describe('WorkplaceSearch', () => { - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders WorkplaceSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(); @@ -55,26 +44,6 @@ describe('WorkplaceSearch', () => { expect(wrapper.find(WorkplaceSearchConfigured)).toHaveLength(1); }); - - it('renders ErrorState when not on SetupGuide', () => { - mockUseRouteMatch.mockReturnValue(false); - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - - const wrapper = shallow(); - - const errorState = wrapper.find(ErrorState); - expect(errorState).toHaveLength(1); - }); - - it('does not render ErrorState when on SetupGuide', () => { - mockUseRouteMatch.mockReturnValue(true); - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - - const wrapper = shallow(); - - const errorState = wrapper.find(ErrorState); - expect(errorState).toHaveLength(0); - }); }); describe('WorkplaceSearchUnconfigured', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index e9332fe81bdab..6233208119c44 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -12,11 +12,8 @@ import { useActions, useValues } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { WorkplaceSearchHeaderActions } from './components/layout'; @@ -39,7 +36,6 @@ import { AccountSettings } from './views/account_settings'; import { ApiKeys } from './views/api_keys'; import { SourcesRouter } from './views/content_sources'; import { SourceAdded } from './views/content_sources/components/source_added'; -import { ErrorState } from './views/error_state'; import { GroupsRouter } from './views/groups'; import { NotFound } from './views/not_found'; import { OAuthAuthorize } from './views/oauth_authorize'; @@ -52,22 +48,9 @@ import { SetupGuide } from './views/setup_guide'; export const WorkplaceSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - const isSetupGuidePath = !!useRouteMatch(SETUP_GUIDE_PATH); if (!config.host) { return ; - } else if (incompatibleVersions) { - return ( - - ); - } else if (errorConnectingMessage && !isSetupGuidePath) { - return ; } return ; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx deleted file mode 100644 index 2c3b49230e394..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorState } from '.'; - -describe('ErrorState', () => { - it('renders', () => { - const wrapper = shallow(); - - const prompt = wrapper.find(ErrorStatePrompt); - expect(prompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx deleted file mode 100644 index fc93896d931f7..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; -import { ViewContentHeader } from '../../components/shared/view_content_header'; - -export const ErrorState: React.FC = () => { - return ( - <> - - - - - - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts index d9f0eefd0fb5c..c8b6c414510fd 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts @@ -7,7 +7,11 @@ import { IScopedClusterClient } from '@kbn/core/server'; -import { Connector, CONNECTORS_INDEX } from '@kbn/search-connectors'; +import { + Connector, + CONNECTORS_INDEX, + MANAGED_CONNECTOR_INDEX_PREFIX, +} from '@kbn/search-connectors'; import { createIndex } from '../indices/create_index'; import { indexOrAliasExists } from '../indices/exists_index'; @@ -20,10 +24,10 @@ export const generateConfig = async (client: IScopedClusterClient, connector: Co if (connector.index_name) { associatedIndex = connector.index_name; } else { - associatedIndex = await generatedIndexName( - client, - connector.name || connector.service_type || 'my-connector' // pass a default name to generate a readable index name rather than gibberish - ); + const indexPrefix = connector.is_native ? MANAGED_CONNECTOR_INDEX_PREFIX : ''; // managed connectors need to be prefixed with `content-` + const connectorReference = connector.name || connector.service_type || 'my-connector'; // pass a default name to generate a readable index name rather than gibberish + + associatedIndex = await generatedIndexName(client, indexPrefix + connectorReference); } if (!indexOrAliasExists(client, associatedIndex)) { diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts index 56f849c551400..374e32861253b 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts @@ -9,22 +9,34 @@ import { v4 as uuidv4 } from 'uuid'; import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import { MANAGED_CONNECTOR_INDEX_PREFIX } from '@kbn/search-connectors'; + import { ErrorCode } from '../../../common/types/error_codes'; import { toAlphanumeric } from '../../../common/utils/to_alphanumeric'; import { indexOrAliasExists } from '../indices/exists_index'; +const addIndexPrefix = (indexName: string, isManagedConnector: boolean): string => { + const indexPrefix = isManagedConnector ? MANAGED_CONNECTOR_INDEX_PREFIX : 'connector-'; + return `${indexPrefix}${indexName}`; +}; + +const addConnectorPrefix = (indexName: string): string => { + return `connector-${indexName}`; +}; + export const generateConnectorName = async ( client: IScopedClusterClient, connectorType: string, - userConnectorName?: string + userConnectorName?: string, + isManagedConnector: boolean = false ): Promise<{ apiKeyName: string; connectorName: string; indexName: string }> => { const prefix = toAlphanumeric(connectorType); if (!prefix || prefix.length === 0) { throw new Error('Connector type or connectorName is required'); } if (userConnectorName) { - let indexName = `connector-${userConnectorName}`; + let indexName = addIndexPrefix(userConnectorName, isManagedConnector); const resultSameName = await indexOrAliasExists(client, indexName); // index with same name doesn't exist if (!resultSameName) { @@ -36,12 +48,14 @@ export const generateConnectorName = async ( } // if the index name already exists, we will generate until it doesn't for 20 times for (let i = 0; i < 20; i++) { - indexName = `connector-${userConnectorName}-${uuidv4().split('-')[1].slice(0, 4)}`; + const randomizedConnectorName = `${userConnectorName}-${uuidv4().split('-')[1].slice(0, 4)}`; + + indexName = addIndexPrefix(randomizedConnectorName, isManagedConnector); const result = await indexOrAliasExists(client, indexName); if (!result) { return { - apiKeyName: indexName, + apiKeyName: addConnectorPrefix(randomizedConnectorName), connectorName: userConnectorName, indexName, }; @@ -49,14 +63,15 @@ export const generateConnectorName = async ( } } else { for (let i = 0; i < 20; i++) { - const connectorName = `${prefix}-${uuidv4().split('-')[1].slice(0, 4)}`; - const indexName = `connector-${connectorName}`; + const randomizedConnectorName = `${prefix}-${uuidv4().split('-')[1].slice(0, 4)}`; + const indexName = addIndexPrefix(randomizedConnectorName, isManagedConnector); const result = await indexOrAliasExists(client, indexName); + if (!result) { return { - apiKeyName: indexName, - connectorName, + apiKeyName: addConnectorPrefix(randomizedConnectorName), + connectorName: randomizedConnectorName, indexName, }; } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts index 6108580463893..8a5f96f54edb6 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts @@ -842,17 +842,19 @@ export function registerConnectorRoutes({ router, log }: RouteDependencies) { body: schema.object({ connectorName: schema.maybe(schema.string()), connectorType: schema.string(), + isManagedConnector: schema.maybe(schema.boolean()), }), }, }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const { connectorType, connectorName } = request.body; + const { connectorType, connectorName, isManagedConnector } = request.body; try { const generatedNames = await generateConnectorName( client, connectorType ?? 'custom', - connectorName + connectorName, + isManagedConnector ); return response.ok({ body: generatedNames, diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.ts index 9db1c37888d4b..43530b27df7f7 100644 --- a/x-pack/plugins/entity_manager/public/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.ts @@ -13,8 +13,9 @@ import { isHttpFetchError, } from '@kbn/server-route-repository-client'; import { type KueryNode, nodeTypes, toKqlExpression } from '@kbn/es-query'; -import type { EntityInstance, EntityMetadata } from '@kbn/entities-schema'; +import type { EntityDefinition, EntityInstance, EntityMetadata } from '@kbn/entities-schema'; import { castArray } from 'lodash'; +import type { EntityDefinitionWithState } from '../../server/lib/entities/types'; import { DisableManagedEntityResponse, EnableManagedEntityResponse, @@ -87,6 +88,24 @@ export class EntityClient { } } + async getEntityDefinition( + id: string + ): Promise<{ definitions: EntityDefinition[] | EntityDefinitionWithState[] }> { + try { + return await this.repositoryClient('GET /internal/entities/definition/{id?}', { + params: { + path: { id }, + query: { page: 1, perPage: 1 }, + }, + }); + } catch (err) { + if (isHttpFetchError(err) && err.body?.statusCode === 403) { + throw new EntityManagerUnauthorizedError(err.body.message); + } + throw err; + } + } + asKqlFilter( entityInstance: { entity: Pick; diff --git a/x-pack/plugins/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/entity_manager/server/lib/entity_client.ts index 7045bee1fc538..35abe63c5fd23 100644 --- a/x-pack/plugins/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/server/lib/entity_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { without } from 'lodash'; import { EntityV2, EntityDefinition, EntityDefinitionUpdate } from '@kbn/entities-schema'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; @@ -23,10 +24,27 @@ import { stopTransforms } from './entities/stop_transforms'; import { deleteIndices } from './entities/delete_index'; import { EntityDefinitionWithState } from './entities/types'; import { EntityDefinitionUpdateConflict } from './entities/errors/entity_definition_update_conflict'; -import { EntitySource, getEntityInstancesQuery } from './queries'; +import { EntitySource, SortBy, getEntityInstancesQuery } from './queries'; import { mergeEntitiesList, runESQLQuery } from './queries/utils'; import { UnknownEntityType } from './entities/errors/unknown_entity_type'; +interface SearchCommon { + start: string; + end: string; + sort?: SortBy; + metadataFields?: string[]; + filters?: string[]; + limit?: number; +} + +export type SearchByType = SearchCommon & { + type: string; +}; + +export type SearchBySources = SearchCommon & { + sources: EntitySource[]; +}; + export class EntityClient { constructor( private options: { @@ -191,17 +209,11 @@ export class EntityClient { type, start, end, + sort, metadataFields = [], filters = [], limit = 10, - }: { - type: string; - start: string; - end: string; - metadataFields?: string[]; - filters?: string[]; - limit?: number; - }) { + }: SearchByType) { const sources = await this.getEntitySources({ type }); if (sources.length === 0) { throw new UnknownEntityType(`No sources found for entity type [${type}]`); @@ -213,6 +225,7 @@ export class EntityClient { end, metadataFields, filters, + sort, limit, }); } @@ -221,21 +234,22 @@ export class EntityClient { sources, start, end, + sort, metadataFields = [], filters = [], limit = 10, - }: { - sources: EntitySource[]; - start: string; - end: string; - metadataFields?: string[]; - filters?: string[]; - limit?: number; - }) { + }: SearchBySources) { const entities = await Promise.all( sources.map(async (source) => { - const mandatoryFields = [source.timestamp_field, ...source.identity_fields]; + const mandatoryFields = [ + ...source.identity_fields, + ...(source.timestamp_field ? [source.timestamp_field] : []), + ...(source.display_name ? [source.display_name] : []), + ]; const metaFields = [...metadataFields, ...source.metadata_fields]; + + // operations on an unmapped field result in a failing query so we verify + // field capabilities beforehand const { fields } = await this.options.esClient.fieldCaps({ index: source.index_patterns, fields: [...mandatoryFields, ...metaFields], @@ -244,15 +258,25 @@ export class EntityClient { const sourceHasMandatoryFields = mandatoryFields.every((field) => !!fields[field]); if (!sourceHasMandatoryFields) { // we can't build entities without id fields so we ignore the source. - // filters should likely behave similarly. + // TODO filters should likely behave similarly. we should also throw + const missingFields = mandatoryFields.filter((field) => !fields[field]); this.options.logger.info( - `Ignoring source for type [${source.type}] with index_patterns [${source.index_patterns}] because some mandatory fields [${mandatoryFields}] are not mapped` + `Ignoring source for type [${source.type}] with index_patterns [${ + source.index_patterns + }] because some mandatory fields [${missingFields.join(', ')}] are not mapped` ); return []; } // but metadata field not being available is fine const availableMetadataFields = metaFields.filter((field) => fields[field]); + if (availableMetadataFields.length < metaFields.length) { + this.options.logger.info( + `Ignoring unmapped fields [${without(metaFields, ...availableMetadataFields).join( + ', ' + )}]` + ); + } const query = getEntityInstancesQuery({ source: { @@ -262,6 +286,7 @@ export class EntityClient { }, start, end, + sort, limit, }); this.options.logger.debug(`Entity query: ${query}`); @@ -271,14 +296,10 @@ export class EntityClient { esClient: this.options.esClient, }); - return rawEntities.map((entity) => { - entity['entity.id'] = source.identity_fields.map((field) => entity[field]).join(':'); - entity['entity.type'] = source.type; - return entity; - }); + return rawEntities; }) ).then((results) => results.flat()); - return mergeEntitiesList(entities).slice(0, limit); + return mergeEntitiesList(sources, entities).slice(0, limit); } } diff --git a/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts b/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts index 539d20c464794..d8b3c9347cdd1 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts @@ -18,19 +18,21 @@ describe('getEntityInstancesQuery', () => { metadata_fields: ['host.name'], filters: [], timestamp_field: 'custom_timestamp_field', + display_name: 'service.id', }, limit: 5, start: '2024-11-20T19:00:00.000Z', end: '2024-11-20T20:00:00.000Z', + sort: { field: 'entity.id', direction: 'DESC' }, }); expect(query).toEqual( - 'FROM logs-*,metrics-*|' + - 'WHERE custom_timestamp_field >= "2024-11-20T19:00:00.000Z"|' + - 'WHERE custom_timestamp_field <= "2024-11-20T20:00:00.000Z"|' + - 'WHERE service.name IS NOT NULL|' + - 'STATS entity.last_seen_timestamp=MAX(custom_timestamp_field),metadata.host.name=VALUES(host.name) BY service.name|' + - 'SORT entity.last_seen_timestamp DESC|' + + 'FROM logs-*, metrics-* | ' + + 'WHERE service.name IS NOT NULL | ' + + 'WHERE custom_timestamp_field >= "2024-11-20T19:00:00.000Z" AND custom_timestamp_field <= "2024-11-20T20:00:00.000Z" | ' + + 'STATS host.name = VALUES(host.name), entity.last_seen_timestamp = MAX(custom_timestamp_field), service.id = MAX(service.id) BY service.name | ' + + 'EVAL entity.type = "service", entity.id = service.name, entity.display_name = COALESCE(service.id, entity.id) | ' + + 'SORT entity.id DESC | ' + 'LIMIT 5' ); }); diff --git a/x-pack/plugins/entity_manager/server/lib/queries/index.ts b/x-pack/plugins/entity_manager/server/lib/queries/index.ts index 9fc7ae00c9aa6..83c25d756c170 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/index.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/index.ts @@ -9,29 +9,35 @@ import { z } from '@kbn/zod'; export const entitySourceSchema = z.object({ type: z.string(), - timestamp_field: z.optional(z.string()).default('@timestamp'), + timestamp_field: z.optional(z.string()), index_patterns: z.array(z.string()), identity_fields: z.array(z.string()), metadata_fields: z.array(z.string()), filters: z.array(z.string()), + display_name: z.optional(z.string()), }); +export interface SortBy { + field: string; + direction: 'ASC' | 'DESC'; +} + export type EntitySource = z.infer; const sourceCommand = ({ source }: { source: EntitySource }) => { - let query = `FROM ${source.index_patterns}`; + let query = `FROM ${source.index_patterns.join(', ')}`; const esMetadataFields = source.metadata_fields.filter((field) => ['_index', '_id'].includes(field) ); if (esMetadataFields.length) { - query += ` METADATA ${esMetadataFields.join(',')}`; + query += ` METADATA ${esMetadataFields.join(', ')}`; } return query; }; -const filterCommands = ({ +const whereCommand = ({ source, start, end, @@ -40,32 +46,65 @@ const filterCommands = ({ start: string; end: string; }) => { - const commands = [ - `WHERE ${source.timestamp_field} >= "${start}"`, - `WHERE ${source.timestamp_field} <= "${end}"`, + const filters = [ + source.identity_fields.map((field) => `${field} IS NOT NULL`).join(' AND '), + ...source.filters, ]; - source.identity_fields.forEach((field) => { - commands.push(`WHERE ${field} IS NOT NULL`); - }); - - source.filters.forEach((filter) => { - commands.push(`WHERE ${filter}`); - }); + if (source.timestamp_field) { + filters.push( + `${source.timestamp_field} >= "${start}" AND ${source.timestamp_field} <= "${end}"` + ); + } - return commands; + return filters.map((filter) => `WHERE ${filter}`).join(' | '); }; const statsCommand = ({ source }: { source: EntitySource }) => { - const aggs = [ - // default 'last_seen' attribute - `entity.last_seen_timestamp=MAX(${source.timestamp_field})`, - ...source.metadata_fields - .filter((field) => !source.identity_fields.some((idField) => idField === field)) - .map((field) => `metadata.${field}=VALUES(${field})`), - ]; + const aggs = source.metadata_fields + .filter((field) => !source.identity_fields.some((idField) => idField === field)) + .map((field) => `${field} = VALUES(${field})`); + + if (source.timestamp_field) { + aggs.push(`entity.last_seen_timestamp = MAX(${source.timestamp_field})`); + } + + if (source.display_name) { + // ideally we want the latest value but there's no command yet + // so we use MAX for now + aggs.push(`${source.display_name} = MAX(${source.display_name})`); + } + + return `STATS ${aggs.join(', ')} BY ${source.identity_fields.join(', ')}`; +}; + +const evalCommand = ({ source }: { source: EntitySource }) => { + const id = + source.identity_fields.length === 1 + ? source.identity_fields[0] + : `CONCAT(${source.identity_fields.join(', ":", ')})`; + + const displayName = source.display_name + ? `COALESCE(${source.display_name}, entity.id)` + : 'entity.id'; + + return `EVAL ${[ + `entity.type = "${source.type}"`, + `entity.id = ${id}`, + `entity.display_name = ${displayName}`, + ].join(', ')}`; +}; + +const sortCommand = ({ source, sort }: { source: EntitySource; sort?: SortBy }) => { + if (sort) { + return `SORT ${sort.field} ${sort.direction}`; + } + + if (source.timestamp_field) { + return `SORT entity.last_seen_timestamp DESC`; + } - return `STATS ${aggs.join(',')} BY ${source.identity_fields.join(',')}`; + return `SORT entity.id ASC`; }; export function getEntityInstancesQuery({ @@ -73,19 +112,22 @@ export function getEntityInstancesQuery({ limit, start, end, + sort, }: { source: EntitySource; limit: number; start: string; end: string; + sort?: SortBy; }): string { const commands = [ sourceCommand({ source }), - ...filterCommands({ source, start, end }), + whereCommand({ source, start, end }), statsCommand({ source }), - `SORT entity.last_seen_timestamp DESC`, + evalCommand({ source }), + sortCommand({ source, sort }), `LIMIT ${limit}`, ]; - return commands.join('|'); + return commands.join(' | '); } diff --git a/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts b/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts index 5d57025671726..df5c8a2a4a826 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { EntitySource } from '.'; import { mergeEntitiesList } from './utils'; describe('mergeEntitiesList', () => { @@ -15,20 +16,23 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList([], entities); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }); }); @@ -38,33 +42,46 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', - 'metadata.agent.name': 'agent-1', - 'metadata.service.environment': ['dev', 'staging'], - 'metadata.only_in_record_1': 'foo', + 'entity.display_name': 'foo', + 'host.name': 'host-1', + 'agent.name': 'agent-1', + 'service.environment': ['dev', 'staging'], + only_in_record_1: 'foo', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-2', 'host-3'], - 'metadata.agent.name': 'agent-2', - 'metadata.service.environment': 'prod', - 'metadata.only_in_record_2': 'bar', + 'entity.display_name': 'foo', + 'host.name': ['host-2', 'host-3'], + 'agent.name': 'agent-2', + 'service.environment': 'prod', + only_in_record_2: 'bar', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name', 'agent.name', 'service.environment', 'only_in_record_1'], + }, + { + metadata_fields: ['host.name', 'agent.name', 'service.environment', 'only_in_record_2'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2', 'host-3'], - 'metadata.agent.name': ['agent-1', 'agent-2'], - 'metadata.service.environment': ['dev', 'staging', 'prod'], - 'metadata.only_in_record_1': 'foo', - 'metadata.only_in_record_2': 'bar', + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2', 'host-3'], + 'agent.name': ['agent-1', 'agent-2'], + 'service.environment': ['dev', 'staging', 'prod'], + only_in_record_1: 'foo', + only_in_record_2: 'bar', }); }); @@ -74,29 +91,78 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', + 'entity.display_name': 'foo', + 'host.name': 'host-1', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-2', + 'entity.display_name': 'foo', + 'host.name': 'host-2', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T16:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-3', + 'entity.display_name': 'foo', + 'host.name': 'host-3', + }, + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-3', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name'], + }, + { + metadata_fields: ['host.name'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2', 'host-3'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2', 'host-3'], + }); + }); + + it('works without entity.last_seen_timestamp', () => { + const entities = [ + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-1', + }, + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-2', + }, + ]; + + const mergedEntities = mergeEntitiesList( + [{ metadata_fields: ['host.name'] }, { metadata_fields: ['host.name'] }] as EntitySource[], + entities + ); + expect(mergedEntities.length).toEqual(1); + expect(mergedEntities[0]).toEqual({ + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }); }); @@ -106,29 +172,43 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', + 'entity.display_name': 'foo', + 'host.name': 'host-1', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-2', + 'entity.display_name': 'foo', + 'host.name': 'host-2', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T16:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name'], + }, + { + metadata_fields: ['host.name'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }); }); }); diff --git a/x-pack/plugins/entity_manager/server/lib/queries/utils.ts b/x-pack/plugins/entity_manager/server/lib/queries/utils.ts index 68f5b0f11aff2..a18f6fb837140 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/utils.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/utils.ts @@ -5,24 +5,33 @@ * 2.0. */ +import { compact, uniq } from 'lodash'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { EntityV2 } from '@kbn/entities-schema'; import { ESQLSearchResponse } from '@kbn/es-types'; -import { uniq } from 'lodash'; - -function mergeEntities(entity1: EntityV2, entity2: EntityV2): EntityV2 { - const merged: EntityV2 = { - ...entity1, - 'entity.last_seen_timestamp': new Date( - Math.max( - Date.parse(entity1['entity.last_seen_timestamp']), - Date.parse(entity2['entity.last_seen_timestamp']) - ) - ).toISOString(), - }; +import { EntitySource } from '.'; + +function getLatestDate(date1?: string, date2?: string) { + if (!date1 && !date2) return; + + return new Date( + Math.max(date1 ? Date.parse(date1) : 0, date2 ? Date.parse(date2) : 0) + ).toISOString(); +} + +function mergeEntities(metadataFields: string[], entity1: EntityV2, entity2: EntityV2): EntityV2 { + const merged: EntityV2 = { ...entity1 }; + + const latestTimestamp = getLatestDate( + entity1['entity.last_seen_timestamp'], + entity2['entity.last_seen_timestamp'] + ); + if (latestTimestamp) { + merged['entity.last_seen_timestamp'] = latestTimestamp; + } for (const [key, value] of Object.entries(entity2).filter(([_key]) => - _key.startsWith('metadata.') + metadataFields.includes(_key) )) { if (merged[key]) { merged[key] = uniq([ @@ -36,7 +45,10 @@ function mergeEntities(entity1: EntityV2, entity2: EntityV2): EntityV2 { return merged; } -export function mergeEntitiesList(entities: EntityV2[]): EntityV2[] { +export function mergeEntitiesList(sources: EntitySource[], entities: EntityV2[]): EntityV2[] { + const metadataFields = uniq( + sources.flatMap((source) => compact([source.timestamp_field, ...source.metadata_fields])) + ); const instances: { [key: string]: EntityV2 } = {}; for (let i = 0; i < entities.length; i++) { @@ -44,7 +56,7 @@ export function mergeEntitiesList(entities: EntityV2[]): EntityV2[] { const id = entity['entity.id']; if (instances[id]) { - instances[id] = mergeEntities(instances[id], entity); + instances[id] = mergeEntities(metadataFields, instances[id], entity); } else { instances[id] = entity; } diff --git a/x-pack/plugins/entity_manager/server/routes/v2/search.ts b/x-pack/plugins/entity_manager/server/routes/v2/search.ts index 0b975da748a86..451ff7cfff43f 100644 --- a/x-pack/plugins/entity_manager/server/routes/v2/search.ts +++ b/x-pack/plugins/entity_manager/server/routes/v2/search.ts @@ -22,20 +22,34 @@ export const searchEntitiesRoute = createEntityManagerServerRoute({ .optional(z.string()) .default(() => moment().subtract(5, 'minutes').toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[start] should be a date in ISO format', }), end: z .optional(z.string()) .default(() => moment().toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[end] should be a date in ISO format', }), + sort: z.optional( + z.object({ + field: z.string(), + direction: z.enum(['ASC', 'DESC']), + }) + ), limit: z.optional(z.number()).default(10), }), }), handler: async ({ request, response, params, logger, getScopedClient }) => { try { - const { type, start, end, limit, filters, metadata_fields: metadataFields } = params.body; + const { + type, + start, + end, + limit, + filters, + sort, + metadata_fields: metadataFields, + } = params.body; const client = await getScopedClient({ request }); const entities = await client.searchEntities({ @@ -44,6 +58,7 @@ export const searchEntitiesRoute = createEntityManagerServerRoute({ metadataFields, start, end, + sort, limit, }); @@ -69,25 +84,32 @@ export const searchEntitiesPreviewRoute = createEntityManagerServerRoute({ .optional(z.string()) .default(() => moment().subtract(5, 'minutes').toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[start] should be a date in ISO format', }), end: z .optional(z.string()) .default(() => moment().toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[end] should be a date in ISO format', }), + sort: z.optional( + z.object({ + field: z.string(), + direction: z.enum(['ASC', 'DESC']), + }) + ), limit: z.optional(z.number()).default(10), }), }), - handler: async ({ request, response, params, logger, getScopedClient }) => { - const { sources, start, end, limit } = params.body; + handler: async ({ request, response, params, getScopedClient }) => { + const { sources, start, end, limit, sort } = params.body; const client = await getScopedClient({ request }); const entities = await client.searchEntitiesBySources({ sources, start, end, + sort, limit, }); diff --git a/x-pack/plugins/features/common/alerting_kibana_privilege.ts b/x-pack/plugins/features/common/alerting_kibana_privilege.ts new file mode 100644 index 0000000000000..4a435b5c651c7 --- /dev/null +++ b/x-pack/plugins/features/common/alerting_kibana_privilege.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Interface for registering an alerting privilege. + * Alerting privilege registration allows plugins to + * specify for which rule types and consumers the feature + * has access to. + */ + +export type AlertingKibanaPrivilege = ReadonlyArray<{ + ruleTypeId: string; + consumers: readonly string[]; +}>; diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 1939d0b5e4e49..a7d39669ef00a 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AlertingKibanaPrivilege } from './alerting_kibana_privilege'; import { FeatureKibanaPrivilegesReference } from './feature_kibana_privileges_reference'; /** @@ -97,47 +98,47 @@ export interface FeatureKibanaPrivileges { alerting?: { rule?: { /** - * List of rule types which users should have full read/write access to when granted this privilege. + * List of rule types and consumers for which users should have full read/write access to when granted this privilege. * @example * ```ts * { - * all: ['my-alert-type-within-my-feature'] + * all: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - all?: readonly string[]; + all?: AlertingKibanaPrivilege; /** - * List of rule types which users should have read-only access to when granted this privilege. + * List of rule types and consumers for which users should have read-only access to when granted this privilege. * @example * ```ts * { - * read: ['my-alert-type'] + * read: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - read?: readonly string[]; + read?: AlertingKibanaPrivilege; }; alert?: { /** - * List of rule types for which users should have full read/write access their alert data to when granted this privilege. + * List of rule types and consumers for which users should have full read/write access their alert data to when granted this privilege. * @example * ```ts * { - * all: ['my-alert-type-within-my-feature'] + * all: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - all?: readonly string[]; + all?: AlertingKibanaPrivilege; /** - * List of rule types for which users should have read-only access to their alert data when granted this privilege. + * List of rule types and consumers for which users should have read-only access to their alert data when granted this privilege. * @example * ```ts * { - * read: ['my-alert-type'] + * read: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - read?: readonly string[]; + read?: AlertingKibanaPrivilege; }; }; diff --git a/x-pack/plugins/features/common/kibana_feature.ts b/x-pack/plugins/features/common/kibana_feature.ts index 3a5d9fc2a0e50..dba79a1663fca 100644 --- a/x-pack/plugins/features/common/kibana_feature.ts +++ b/x-pack/plugins/features/common/kibana_feature.ts @@ -11,6 +11,7 @@ import { LicenseType } from '@kbn/licensing-plugin/common/types'; import { FeatureKibanaPrivileges } from './feature_kibana_privileges'; import { SubFeatureConfig, SubFeature as KibanaSubFeature } from './sub_feature'; import { ReservedKibanaPrivilege } from './reserved_kibana_privilege'; +import { AlertingKibanaPrivilege } from './alerting_kibana_privilege'; /** * Enum for allowed feature scope values. @@ -107,11 +108,12 @@ export interface KibanaFeatureConfig { catalogue?: readonly string[]; /** - * If your feature grants access to specific Alert Types, you can specify them here to control visibility based on the current space. - * Include both Alert Types registered by the feature and external Alert Types such as built-in - * Alert Types and Alert Types provided by other features to which you wish to grant access. + * If your feature grants access to specific rule types, you can specify them here to control visibility based on the current space. + * Include both rule types registered by the feature and external rule types such as built-in + * rule types and rule types provided by other features to which you wish to grant access. For each rule type + * you can specify the consumers the feature has access to. */ - alerting?: readonly string[]; + alerting?: AlertingKibanaPrivilege; /** * If your feature grants access to specific case types, you can specify them here to control visibility based on the current space. diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index b8df9e9c2117b..b5614562f18a4 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -881,6 +881,9 @@ exports[`buildOSSFeatures with a basic license returns the indexPatterns feature Array [ Object { "privilege": Object { + "api": Array [ + "indexPatterns:manage", + ], "app": Array [ "kibana", ], @@ -1520,6 +1523,9 @@ exports[`buildOSSFeatures with a enterprise license returns the indexPatterns fe Array [ Object { "privilege": Object { + "api": Array [ + "indexPatterns:manage", + ], "app": Array [ "kibana", ], diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts index c7d501bb17cf8..c4e542a7ebcde 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts @@ -62,11 +62,11 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, }, @@ -96,10 +96,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -134,11 +134,11 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, }, @@ -171,10 +171,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -205,12 +205,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], - read: ['alerting-read-type-alerts'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type-alerts', consumers: ['foo'] }], }, }, cases: { @@ -239,10 +239,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -278,12 +278,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], - read: ['alerting-read-type-alerts'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type-alerts', consumers: ['foo'] }], }, }, cases: { @@ -323,10 +323,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -355,10 +355,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -390,7 +390,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -436,10 +436,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -471,10 +471,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -506,10 +506,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -538,10 +538,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -573,7 +573,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -619,10 +619,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -654,10 +654,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -689,10 +689,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -721,10 +721,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -757,7 +757,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -804,12 +804,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-another-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -843,11 +843,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -887,12 +887,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -921,10 +921,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -956,7 +956,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -994,12 +994,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-read-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1032,11 +1032,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-read-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1076,10 +1076,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1108,10 +1108,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1144,7 +1144,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -1191,12 +1191,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-another-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1228,10 +1228,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1390,8 +1390,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -1438,8 +1438,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, alert: { all: [], @@ -1476,8 +1476,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, alert: { all: [], @@ -1521,10 +1521,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1553,10 +1553,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1612,12 +1612,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { all: [], - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1650,11 +1650,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts index a9d7336ea0a22..45518004430a4 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts @@ -8,6 +8,7 @@ import _ from 'lodash'; import type { LicenseType } from '@kbn/licensing-plugin/server'; +import { AlertingKibanaPrivilege } from '../../common/alerting_kibana_privilege'; import type { FeatureKibanaPrivileges, KibanaFeature } from '..'; import { subFeaturePrivilegeIterator } from './sub_feature_privilege_iterator'; @@ -108,26 +109,46 @@ function mergeWithSubFeatures( subFeaturePrivilege.savedObject.read ); + /** + * Merges all alerting rule types and consumers + * from features and sub features. + * Removes duplicated values. + */ + const mergeAlertingEntries = (entries: AlertingKibanaPrivilege): AlertingKibanaPrivilege => { + const alertingMap = new Map>(); + + for (const entry of entries) { + const consumers = alertingMap.get(entry.ruleTypeId) ?? new Set(); + entry.consumers.forEach((consumer) => consumers.add(consumer)); + alertingMap.set(entry.ruleTypeId, consumers); + } + + return Array.from(alertingMap).map(([ruleTypeId, consumers]) => ({ + ruleTypeId, + consumers: Array.from(consumers), + })); + }; + mergedConfig.alerting = { rule: { - all: mergeArrays( - mergedConfig.alerting?.rule?.all ?? [], - subFeaturePrivilege.alerting?.rule?.all ?? [] - ), - read: mergeArrays( - mergedConfig.alerting?.rule?.read ?? [], - subFeaturePrivilege.alerting?.rule?.read ?? [] - ), + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.all ?? []), + ...(subFeaturePrivilege.alerting?.rule?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.read ?? []), + ...(subFeaturePrivilege.alerting?.rule?.read ?? []), + ]), }, alert: { - all: mergeArrays( - mergedConfig.alerting?.alert?.all ?? [], - subFeaturePrivilege.alerting?.alert?.all ?? [] - ), - read: mergeArrays( - mergedConfig.alerting?.alert?.read ?? [], - subFeaturePrivilege.alerting?.alert?.read ?? [] - ), + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.all ?? []), + ...(subFeaturePrivilege.alerting?.alert?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.read ?? []), + ...(subFeaturePrivilege.alerting?.alert?.read ?? []), + ]), }, }; diff --git a/x-pack/plugins/features/server/feature_registry.test.ts b/x-pack/plugins/features/server/feature_registry.test.ts index 08da08e0a19bd..9ed7a207560b0 100644 --- a/x-pack/plugins/features/server/feature_registry.test.ts +++ b/x-pack/plugins/features/server/feature_registry.test.ts @@ -868,404 +868,688 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents privileges from specifying alerting/rule entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: { - all: { - alerting: { - rule: { - all: ['foo', 'bar'], - read: ['baz'], + describe('alerting', () => { + it(`prevents privileges from specifying rule types that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + read: [{ ruleTypeId: 'baz', consumers: ['test-feature'] }], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], - }, - read: { - alerting: { - rule: { - read: ['foo', 'bar', 'baz'], + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.all has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all has unknown ruleTypeId: foo"` + ); + }); - it(`prevents privileges from specifying alerting/alert entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: { - all: { - alerting: { - alert: { - all: ['foo', 'bar'], - read: ['baz'], + it(`prevents privileges from specifying rule types entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + read: [{ ruleTypeId: 'baz', consumers: ['test-feature'] }], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], - }, - read: { - alerting: { - alert: { - read: ['foo', 'bar', 'baz'], + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + alert: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.all has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all has unknown ruleTypeId: foo"` + ); + }); - it(`prevents features from specifying alerting/rule entries that don't exist at the privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: { - all: { - alerting: { - rule: { - all: ['foo'], + it(`prevents features from specifying rule types that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - read: { - alerting: { - rule: { - all: ['foo'], + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], + }, + ui: [], + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + }, + ], + }, + ], + }, + ], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying rule types entries that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: { + all: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - subFeatures: [ - { - name: 'my sub feature', - privilegeGroups: [ - { - groupType: 'independent', - privileges: [ - { - id: 'cool-sub-feature-privilege', - name: 'cool privilege', - includeIn: 'none', - savedObject: { - all: [], - read: [], - }, - ui: [], - alerting: { - rule: { - all: ['bar'], + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], }, + ui: [], + alerting: { + alert: { + all: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + }, + ], + }, + ], + }, + ], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents reserved privileges from specifying rule types that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], }, }, - ], + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, ], }, - ], - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved has unknown ruleTypeId: foo"` + ); + }); - it(`prevents features from specifying alerting/alert entries that don't exist at the privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: { - all: { - alerting: { - alert: { - all: ['foo'], + it(`prevents reserved privileges from specifying rule types entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], + ], }, - read: { - alerting: { - alert: { - all: ['foo'], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved has unknown ruleTypeId: foo"` + ); + }); + + it(`prevents features from specifying rule types that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], + ], }, - }, - subFeatures: [ - { - name: 'my sub feature', - privilegeGroups: [ + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying rule types entries that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: null, + reserved: { + description: 'something', + privileges: [ { - groupType: 'independent', - privileges: [ - { - id: 'cool-sub-feature-privilege', - name: 'cool privilege', - includeIn: 'none', - savedObject: { - all: [], - read: [], - }, - ui: [], - alerting: { - alert: { - all: ['bar'], - }, + id: 'reserved', + privilege: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], }, }, - ], + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, ], }, - ], - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); - it(`prevents reserved privileges from specifying alerting/rule entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - rule: { - all: ['foo', 'bar', 'baz'], - }, + it(`prevents privileges from specifying rule types without consumers`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: [] }], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: [] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'foo', consumers: [] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ], - }, - }; + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.reserved has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"[alerting.0.consumers]: array size is [0], but cannot be smaller than [1]"` + ); + }); - it(`prevents reserved privileges from specifying alerting/alert entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - alert: { - all: ['foo', 'bar', 'baz'], - }, + it(`prevents privileges from specifying consumers entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['not-exist'] }], + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ], - }, - }; + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.reserved has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all.bar has unknown consumer: not-exist"` + ); + }); - it(`prevents features from specifying alerting/rule entries that don't exist at the reserved privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - rule: { - all: ['foo', 'bar'], - }, + it(`prevents features from specifying consumers that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: ['test-feature', 'should-exist', 'foo'] }], + privileges: { + all: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], + }, + ui: [], + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['foo'] }], + }, + }, + }, + ], + }, + ], }, ], - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting consumers which are not granted to any privileges: should-exist"` + ); + }); - it(`prevents features from specifying alerting/alert entries that don't exist at the reserved privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - alert: { - all: ['foo', 'bar'], + it(`prevents reserved privileges from specifying consumers that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['not-exist'] }], + }, + }, + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + }, + ], + }, + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved.bar has unknown consumer: not-exist"` + ); + }); + + it(`prevents features from specifying consumers that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: ['test-feature', 'should-exist'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - ], - }, - }; + ], + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting consumers which are not granted to any privileges: should-exist"` + ); + }); }); it(`prevents privileges from specifying cases entries that don't exist at the root level`, () => { @@ -2068,11 +2352,15 @@ describe('FeatureRegistry', () => { all: { ui: [], savedObject: { all: [], read: [] }, - alerting: { alert: { all: ['one'] } }, + alerting: { + alert: { + all: [{ ruleTypeId: 'one', consumers: ['featureE'] }], + }, + }, }, read: { ui: [], savedObject: { all: [], read: [] } }, }, - alerting: ['one'], + alerting: [{ ruleTypeId: 'one', consumers: ['featureE'] }], }, ]; features.forEach((f) => registry.registerKibanaFeature(f)); diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index ce444c41e477d..3923eb31dbecb 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -11,6 +11,7 @@ import { difference } from 'lodash'; import { Capabilities as UICapabilities } from '@kbn/core/server'; import { KibanaFeatureConfig, KibanaFeatureScope } from '../common'; import { FeatureKibanaPrivileges, ElasticsearchFeatureConfig } from '.'; +import { AlertingKibanaPrivilege } from '../common/alerting_kibana_privilege'; // Each feature gets its own property on the UICapabilities object, // but that object has a few built-in properties which should not be overwritten. @@ -63,7 +64,13 @@ const managementSchema = schema.recordOf( listOfCapabilitiesSchema ); const catalogueSchema = listOfCapabilitiesSchema; -const alertingSchema = schema.arrayOf(schema.string()); +const alertingSchema = schema.arrayOf( + schema.object({ + ruleTypeId: schema.string(), + consumers: schema.arrayOf(schema.string(), { minSize: 1 }), + }) +); + const casesSchema = schema.arrayOf(schema.string()); const appCategorySchema = schema.object({ @@ -331,7 +338,14 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { const unseenCatalogue = new Set(catalogue); - const unseenAlertTypes = new Set(alerting); + const alertingMap = new Map( + alerting.map(({ ruleTypeId, consumers }) => [ruleTypeId, new Set(consumers)]) + ); + + const unseenAlertingRyleTypeIds = new Set(alertingMap.keys()); + const unseenAlertingConsumers = new Set( + alerting.flatMap(({ consumers }) => Array.from(consumers.values())) + ); const unseenCasesTypes = new Set(cases); @@ -362,20 +376,40 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { } function validateAlertingEntry(privilegeId: string, entry: FeatureKibanaPrivileges['alerting']) { - const all: string[] = [...(entry?.rule?.all ?? []), ...(entry?.alert?.all ?? [])]; - const read: string[] = [...(entry?.rule?.read ?? []), ...(entry?.alert?.read ?? [])]; + const seenRuleTypeIds = new Set(); + const seenConsumers = new Set(); + + const validateAlertingPrivilege = (alertingPrivilege?: AlertingKibanaPrivilege) => { + for (const { ruleTypeId, consumers } of alertingPrivilege ?? []) { + if (!alertingMap.has(ruleTypeId)) { + throw new Error( + `Feature privilege ${feature.id}.${privilegeId} has unknown ruleTypeId: ${ruleTypeId}` + ); + } + + const alertingMapConsumers = alertingMap.get(ruleTypeId)!; + + for (const consumer of consumers) { + if (!alertingMapConsumers.has(consumer)) { + throw new Error( + `Feature privilege ${feature.id}.${privilegeId}.${ruleTypeId} has unknown consumer: ${consumer}` + ); + } - all.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); - read.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); + seenConsumers.add(consumer); + } - const unknownAlertingEntries = difference([...all, ...read], alerting); - if (unknownAlertingEntries.length > 0) { - throw new Error( - `Feature privilege ${ - feature.id - }.${privilegeId} has unknown alerting entries: ${unknownAlertingEntries.join(', ')}` - ); - } + seenRuleTypeIds.add(ruleTypeId); + } + }; + + validateAlertingPrivilege(entry?.rule?.all); + validateAlertingPrivilege(entry?.rule?.read); + validateAlertingPrivilege(entry?.alert?.all); + validateAlertingPrivilege(entry?.alert?.read); + + seenRuleTypeIds.forEach((ruleTypeId: string) => unseenAlertingRyleTypeIds.delete(ruleTypeId)); + seenConsumers.forEach((consumer: string) => unseenAlertingConsumers.delete(consumer)); } function validateCasesEntry(privilegeId: string, entry: FeatureKibanaPrivileges['cases']) { @@ -510,12 +544,22 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { ); } - if (unseenAlertTypes.size > 0) { + if (unseenAlertingRyleTypeIds.size > 0) { + throw new Error( + `Feature ${ + feature.id + } specifies alerting rule types which are not granted to any privileges: ${Array.from( + unseenAlertingRyleTypeIds.keys() + ).join(',')}` + ); + } + + if (unseenAlertingConsumers.size > 0) { throw new Error( `Feature ${ feature.id - } specifies alerting entries which are not granted to any privileges: ${Array.from( - unseenAlertTypes.values() + } specifies alerting consumers which are not granted to any privileges: ${Array.from( + unseenAlertingConsumers.keys() ).join(',')}` ); } diff --git a/x-pack/plugins/features/server/oss_features.ts b/x-pack/plugins/features/server/oss_features.ts index 19001fe19547e..0f243e7e6bda8 100644 --- a/x-pack/plugins/features/server/oss_features.ts +++ b/x-pack/plugins/features/server/oss_features.ts @@ -401,6 +401,7 @@ export const buildOSSFeatures = ({ read: [], }, ui: ['save'], + api: ['indexPatterns:manage'], }, read: { app: ['kibana'], diff --git a/x-pack/plugins/fleet/common/services/agent_status.test.ts b/x-pack/plugins/fleet/common/services/agent_status.test.ts new file mode 100644 index 0000000000000..5c64e2d023ddc --- /dev/null +++ b/x-pack/plugins/fleet/common/services/agent_status.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { Agent } from '../types'; + +import { isStuckInUpdating } from './agent_status'; + +describe('isStuckInUpdating', () => { + it('should return true if agent is active and in failed upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_FAILED', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(true); + }); + + it('should return false if agent is active and in watching upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_WATCHING', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is active and in rollback upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_ROLLBACK', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is updating and in schedule upgrade state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + upgrade_details: { + state: 'UPG_SCHEDULED', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is updating and in downloading upgrade state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + upgrade_details: { + state: 'UPG_DOWNLOADING', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return true if agent is updating no upgrade details state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(true); + }); +}); diff --git a/x-pack/plugins/fleet/common/services/agent_status.ts b/x-pack/plugins/fleet/common/services/agent_status.ts index 78726667f3b13..42b586d7552ae 100644 --- a/x-pack/plugins/fleet/common/services/agent_status.ts +++ b/x-pack/plugins/fleet/common/services/agent_status.ts @@ -60,13 +60,15 @@ export function buildKueryForInactiveAgents() { export const AGENT_UPDATING_TIMEOUT_HOURS = 2; export function isStuckInUpdating(agent: Agent): boolean { + const hasTimedOut = (upgradeStartedAt: string) => + Date.now() - Date.parse(upgradeStartedAt) > AGENT_UPDATING_TIMEOUT_HOURS * 60 * 60 * 1000; return ( (agent.status !== 'offline' && agent.active && isAgentInFailedUpgradeState(agent)) || (agent.status === 'updating' && !!agent.upgrade_started_at && !agent.upgraded_at && - Date.now() - Date.parse(agent.upgrade_started_at) > - AGENT_UPDATING_TIMEOUT_HOURS * 60 * 60 * 1000) + hasTimedOut(agent.upgrade_started_at) && + !agent.upgrade_details?.state) ); } diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index 0918fcaa08d7f..8f96c3ffc197d 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -469,6 +469,45 @@ describe('Fleet - packageToPackagePolicy', () => { }); }); + it('returns package policy with inputs variables', () => { + const mockPackageWithPolicyTemplates = { + ...mockPackage, + policy_templates: [ + { inputs: [{ type: 'foo' }] }, + { inputs: [{ type: 'bar', vars: [{ default: 'bar-var-value', name: 'var-name' }] }] }, + ], + } as unknown as PackageInfo; + + expect( + packageToPackagePolicy( + mockPackageWithPolicyTemplates, + 'policy-id-1', + 'default', + 'pkgPolicy-1' + ) + ).toEqual({ + policy_id: 'policy-id-1', + policy_ids: ['policy-id-1'], + namespace: 'default', + enabled: true, + inputs: [ + { type: 'foo', enabled: true, streams: [] }, + { + type: 'bar', + enabled: true, + streams: [], + vars: { 'var-name': { value: 'bar-var-value' } }, + }, + ], + name: 'pkgPolicy-1', + package: { + name: 'mock-package', + title: 'Mock package', + version: '0.0.0', + }, + }); + }); + it('returns package policy with multiple policy templates (aka has integrations', () => { expect( packageToPackagePolicy( diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index a830cfd903007..6aed76b0a115b 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -147,9 +147,7 @@ export const packageToPackagePolicyInputs = ( return stream; }); - // If non-integration package, collect input-level vars, otherwise skip them, - // we do not support input-level vars for packages with integrations yet) - if (packageInput.vars?.length && !hasIntegrations) { + if (packageInput.vars?.length) { varsForInput = packageInput.vars.reduce(varsReducer, {}); } diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index fb19953a1f731..0d180a0f4935a 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -46,7 +46,7 @@ export interface NewAgentPolicy { global_data_tags?: GlobalDataTag[]; monitoring_pprof_enabled?: boolean; monitoring_http?: { - enabled: boolean; + enabled?: boolean; host?: string; port?: number; buffer?: { diff --git a/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.ts b/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.ts new file mode 100644 index 0000000000000..2003a9f165d3b --- /dev/null +++ b/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.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 { ADD_PACKAGE_POLICY_BTN } from '../../screens/fleet'; +import { login } from '../../tasks/login'; + +describe('View agentless policy details', () => { + beforeEach(() => { + login(); + cy.intercept('/api/fleet/agent_policies/policy-1', { + item: { + id: 'policy-1', + name: 'Agentless policy for cspm-1', + description: '', + namespace: 'default', + monitoring_enabled: ['logs', 'metrics'], + status: 'active', + supports_agentless: true, + package_policies: [ + { + id: 'cspm-1', + name: 'cspm-1', + policy_id: 'policy-1', + policy_ids: ['policy-1'], + inputs: [], + }, + ], + }, + }); + }); + + it('should not show the add integration button if the policy support agentless', () => { + cy.visit('/app/fleet/policies/policy-1'); + cy.getBySel(ADD_PACKAGE_POLICY_BTN).should('not.exist'); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts index da4d0e2c2594d..9d2f6ba4ccf01 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts @@ -20,7 +20,8 @@ jest.mock('../../../hooks/use_locator', () => { }); const apmLocatorMock = useLocatorModule.useLocator('APM_LOCATOR')?.getUrl; -describe('useApmServiceHref hook', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201876 +describe.skip('useApmServiceHref hook', () => { afterEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx index 7ec72369f338e..17c1b24dec817 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx @@ -17,7 +17,8 @@ import { validatePackagePolicy } from '../../services'; import { StepConfigurePackagePolicy } from './step_configure_package'; -describe('StepConfigurePackage', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201598 +describe.skip('StepConfigurePackage', () => { let packageInfo: PackageInfo; let packagePolicy: NewPackagePolicy; const mockUpdatePackagePolicy = jest.fn().mockImplementation((val: any) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index 83e18d77f2a06..3fe016d5e35f1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -400,45 +400,46 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ }} {...rest} search={{ - toolsRight: agentPolicy.is_managed - ? [] - : [ - { - application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { - path: pagePathGetters.integrations_all({})[1], - state: { forAgentPolicyId: agentPolicy.id }, - }); - }} - data-test-subj="addPackagePolicyButton" - tooltip={ - !canWriteIntegrationPolicies - ? { - content: missingSecurityConfiguration ? ( - - ) : ( - - ), - } - : undefined - } - > - - , - ], + toolsRight: + agentPolicy.is_managed || agentPolicy.supports_agentless + ? [] + : [ + { + application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { + path: pagePathGetters.integrations_all({})[1], + state: { forAgentPolicyId: agentPolicy.id }, + }); + }} + data-test-subj="addPackagePolicyButton" + tooltip={ + !canWriteIntegrationPolicies + ? { + content: missingSecurityConfiguration ? ( + + ) : ( + + ), + } + : undefined + } + > + + , + ], box: { incremental: true, schema: true, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx index 255b2efb94026..b56494311f6a9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx @@ -15,7 +15,8 @@ import type { OutputsForAgentPolicy } from '../../../../../../../common/types'; import { AgentPolicyOutputsSummary } from './agent_policy_outputs_summary'; -describe('MultipleAgentPolicySummaryLine', () => { +// FLAKY: https://github.com/elastic/kibana/issues/200819 +describe.skip('MultipleAgentPolicySummaryLine', () => { let testRenderer: TestRenderer; const outputsForPolicy: OutputsForAgentPolicy = { agentPolicyId: 'policy-1', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx index 4c34cb8824af3..40017125a223b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx @@ -35,7 +35,8 @@ const renderComponent = (props: React.ComponentProps) ); }; -describe('AgentStatusFilter', () => { +// FLAKY: https://github.com/elastic/kibana/issues/200788 +describe.skip('AgentStatusFilter', () => { it('Renders all statuses', () => { const { getByText } = renderComponent({ selectedStatus: [], diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx index f3fcdfabc7722..bfd9028f5d0ce 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { fireEvent, act } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../../../../../mock'; @@ -44,13 +44,9 @@ test('it should allow to add a new host', async () => { test('it should allow to remove an host', async () => { const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); - await act(async () => { - const deleteRowEl = await utils.container.querySelector('[aria-label="Delete row"]'); - if (!deleteRowEl) { - throw new Error('Delete row button not found'); - } - fireEvent.click(deleteRowEl); - }); + const deleteRowEl = await utils.container.querySelector('[aria-label="Delete row"]'); + expect(deleteRowEl).not.toBeNull(); + fireEvent.click(deleteRowEl!); expect(mockOnChange).toHaveBeenCalledWith(['http://host2.com']); }); @@ -95,7 +91,7 @@ test('Should display errors in order', async () => { { message: 'Error 3', index: 2 }, ] ); - await act(async () => { + await waitFor(async () => { const errors = await utils.queryAllByText(/Error [1-3]/); expect(errors[0]).toHaveTextContent('Error 1'); expect(errors[1]).toHaveTextContent('Error 2'); @@ -126,18 +122,14 @@ test('Should remove error when item deleted', async () => { ); }); - await act(async () => { - const deleteRowButtons = await utils.container.querySelectorAll('[aria-label="Delete row"]'); - if (deleteRowButtons.length !== 3) { - throw new Error('Delete row buttons not found'); - } + const deleteRowButtons = await utils.container.querySelectorAll('[aria-label="Delete row"]'); + expect(deleteRowButtons.length).toEqual(3); - fireEvent.click(deleteRowButtons[1]); - expect(mockOnChange).toHaveBeenCalled(); + fireEvent.click(deleteRowButtons[1]); + expect(mockOnChange).toHaveBeenCalled(); - const renderedErrors = await utils.queryAllByText(/Error [1-3]/); - expect(renderedErrors).toHaveLength(2); - expect(renderedErrors[0]).toHaveTextContent('Error 1'); - expect(renderedErrors[1]).toHaveTextContent('Error 3'); - }); + const renderedErrors = await utils.queryAllByText(/Error [1-3]/); + expect(renderedErrors).toHaveLength(2); + expect(renderedErrors[0]).toHaveTextContent('Error 1'); + expect(renderedErrors[1]).toHaveTextContent('Error 3'); }); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx index 6c9be4796f205..400c5f3a5aa6d 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx @@ -7,7 +7,7 @@ import React, { lazy, memo } from 'react'; import { Route } from '@kbn/shared-ux-router'; -import { act, cleanup } from '@testing-library/react'; +import { act } from '@testing-library/react'; import { INTEGRATIONS_ROUTING_PATHS, pagePathGetters } from '../../../../constants'; import type { @@ -65,10 +65,6 @@ describe('When on integration detail', () => { act(() => testRenderer.mountHistory.push(detailPageUrlPath)); }); - afterEach(() => { - cleanup(); - }); - describe('and the package is installed', () => { beforeEach(async () => { await render(); diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx index 19709c55665fc..13ecfc2282226 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx @@ -8,7 +8,7 @@ import './agent_enrollment_flyout.test.mocks'; import React from 'react'; -import { act, cleanup, fireEvent, waitFor } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import type { RenderResult } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../mock'; @@ -23,11 +23,8 @@ import type { FlyOutProps } from './types'; import { AgentEnrollmentFlyout } from '.'; const render = (props?: Partial) => { - cleanup(); const renderer = createFleetTestRendererMock(); - const results = renderer.render(); - - return results; + return renderer.render(); }; const testAgentPolicy: AgentPolicy = { @@ -46,7 +43,7 @@ const testAgentPolicy: AgentPolicy = { describe('', () => { let results: RenderResult; - beforeEach(async () => { + beforeEach(() => { jest.mocked(useAuthz).mockReturnValue({ fleet: { readAgentPolicies: true, @@ -88,10 +85,6 @@ describe('', () => { agentPolicies: [{ id: 'fleet-server-policy' } as AgentPolicy], refreshAgentPolicies: jest.fn(), }); - - act(() => { - results = render(); - }); }); afterEach(() => { @@ -113,6 +106,8 @@ describe('', () => { describe('managed instructions', () => { it('uses the agent policy selection step', () => { + results = render(); + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); @@ -154,24 +149,22 @@ describe('', () => { describe('standalone instructions', () => { function goToStandaloneTab() { - act(() => { - fireEvent.click(results.getByTestId('standaloneTab')); - }); + fireEvent.click(results.getByTestId('standaloneTab')); } - beforeEach(() => { + it('uses the agent policy selection step', async () => { results = render({ isIntegrationFlow: true, }); - }); - it('uses the agent policy selection step', async () => { goToStandaloneTab(); - expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); - expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); - expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); - expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + await waitFor(() => { + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); + expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); + expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); + expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + }); }); describe('with a specific policy', () => { @@ -185,13 +178,15 @@ describe('', () => { }); }); - it('does not use either of the agent policy selection or enrollment key steps', () => { + it('does not use either of the agent policy selection or enrollment key steps', async () => { goToStandaloneTab(); - expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); - expect(results.queryByTestId('agent-policy-selection-step')).toBeNull(); - expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); - expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + await waitFor(() => { + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); + expect(results.queryByTestId('agent-policy-selection-step')).toBeNull(); + expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); + expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + }); }); }); }); diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx index 86cbd1a1a5a10..6cf1f68673ac7 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx @@ -7,16 +7,14 @@ import React from 'react'; -import { cleanup, waitFor } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../mock'; import { RootPrivilegesCallout } from './root_privileges_callout'; -// FLAKY: https://github.com/elastic/kibana/issues/201210 -describe.skip('RootPrivilegesCallout', () => { +describe('RootPrivilegesCallout', () => { function render(rootIntegrations?: Array<{ name: string; title: string }>) { - cleanup(); const renderer = createFleetTestRendererMock(); const results = renderer.render(); diff --git a/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx b/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx index 100a6f67ad838..22efe3f84d435 100644 --- a/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx +++ b/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import React from 'react'; import type { TestRenderer } from '../mock'; @@ -31,7 +31,7 @@ describe('MultipleAgentPolicySummaryLine', () => { testRenderer = createFleetTestRendererMock(); }); - test('it should only render the policy name when there is only one policy', async () => { + test('it should only render the policy name when there is only one policy', () => { const results = render([{ name: 'Test policy', revision: 2 }] as AgentPolicy[]); expect(results.container.textContent).toBe('Test policyrev. 2'); expect(results.queryByTestId('agentPolicyNameLink')).toBeInTheDocument(); @@ -48,19 +48,18 @@ describe('MultipleAgentPolicySummaryLine', () => { expect(results.queryByTestId('agentPoliciesNumberBadge')).toBeInTheDocument(); expect(results.container.textContent).toBe('Test policy 1+2'); - await act(async () => { - fireEvent.click(results.getByTestId('agentPoliciesNumberBadge')); - }); - expect(results.queryByTestId('agentPoliciesPopover')).toBeInTheDocument(); - expect(results.queryByTestId('agentPoliciesPopoverButton')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0001')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0002')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0003')).toBeInTheDocument(); + fireEvent.click(results.getByTestId('agentPoliciesNumberBadge')); - await act(async () => { - fireEvent.click(results.getByTestId('agentPoliciesPopoverButton')); + await waitFor(() => { + expect(results.queryByTestId('agentPoliciesPopover')).toBeInTheDocument(); + expect(results.queryByTestId('agentPoliciesPopoverButton')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0001')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0002')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0003')).toBeInTheDocument(); }); + fireEvent.click(results.getByTestId('agentPoliciesPopoverButton')); + expect(results.queryByTestId('manageAgentPoliciesModal')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index b7759438986d5..3c4b2c7f1bf3e 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { act } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; import { createIntegrationsTestRendererMock } from '../mock'; @@ -109,8 +109,8 @@ function createMockPackagePolicy( ...props, }; } -// FLAKY: https://github.com/elastic/kibana/issues/191804 -describe.skip('PackagePolicyActionsMenu', () => { + +describe('PackagePolicyActionsMenu', () => { beforeAll(() => { useMultipleAgentPoliciesMock.mockReturnValue({ canUseMultipleAgentPolicies: false }); }); @@ -119,7 +119,8 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy({ hasUpgrade: false }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + + await waitFor(() => { expect(utils.queryByTestId('PackagePolicyActionsUpgradeItem')).toBeNull(); }); }); @@ -129,7 +130,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); expect(upgradeButton).not.toBeDisabled(); }); @@ -140,7 +141,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); expect(upgradeButton).toBeDisabled(); }); @@ -150,7 +151,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: true }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).toBeNull(); }); }); @@ -159,7 +160,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: false }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).not.toBeNull(); }); }); @@ -168,7 +169,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: false, supports_agentless: true }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).not.toBeNull(); }); }); @@ -177,7 +178,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).not.toBeNull(); }); }); @@ -186,7 +187,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: true }); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).toBeNull(); }); }); @@ -195,7 +196,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ supports_agentless: true }); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).toBeNull(); }); }); @@ -204,7 +205,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const editButton = utils.getByTestId('PackagePolicyActionsEditItem'); expect(editButton).not.toHaveAttribute('disabled'); expect(editButton).toHaveAttribute('href'); @@ -227,7 +228,7 @@ describe.skip('PackagePolicyActionsMenu', () => { agentPolicies: [], packagePolicy, }); - await act(async () => { + await waitFor(() => { const editButton = utils.getByTestId('PackagePolicyActionsEditItem'); expect(editButton).not.toHaveAttribute('disabled'); expect(editButton).toHaveAttribute('href'); diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx index a71172411ef9d..75fce0507f5af 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { EuiContextMenuItem } from '@elastic/eui'; @@ -24,13 +24,15 @@ jest.mock('../hooks', () => { useMultipleAgentPolicies: jest.fn(), useStartServices: jest.fn().mockReturnValue({ notifications: { - toasts: { addSuccess: jest.fn() }, + toasts: { addSuccess: jest.fn(), addDanger: jest.fn() }, }, }), sendGetAgents: jest.fn(), useConfig: jest.fn().mockReturnValue({ agents: { enabled: true }, }), + sendDeletePackagePolicy: jest.fn().mockResolvedValue({ data: [] }), + sendDeleteAgentPolicy: jest.fn().mockResolvedValue({ data: [] }), }; }); @@ -56,6 +58,7 @@ function renderMenu({ onClick={() => { deletePackagePoliciesPrompt(packagePolicyIds, () => {}); }} + data-test-subj="deleteIntegrationBtn" > Delete integration @@ -134,8 +137,7 @@ function createMockAgentPolicies( } } -// FLAKY: https://github.com/elastic/kibana/issues/199204 -describe.skip('PackagePolicyDeleteProvider', () => { +describe('PackagePolicyDeleteProvider', () => { it('Should show delete integrations action and cancel modal', async () => { useMultipleAgentPoliciesMock.mockReturnValue({ canUseMultipleAgentPolicies: false }); sendGetAgentsMock.mockResolvedValue({ @@ -155,15 +157,16 @@ describe.skip('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + await waitFor(() => { + const calloutText = utils.getByTestId('affectedAgentsCallOut').textContent; + expect(calloutText).toContain('This action will affect 5 agents.'); + expect(calloutText).toContain('is already in use by some of your agents'); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.getByText('This action will affect 5 agents.')).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.getAllByText(/is already in use by some of your agents./).length).toBe(1); }); it('When multiple agent policies are present and agents are enrolled show additional warnings', async () => { @@ -185,18 +188,19 @@ describe.skip('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + const calloutText = utils.getByTestId('affectedAgentsCallOut').textContent; + expect(calloutText).toContain('This action will affect 5 agents.'); + expect(utils.getByTestId('sharedAgentPolicyCallOut').textContent).toContain( + 'This integration is shared by multiple agent policies.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.getByText('This action will affect 5 agents.')).toBeInTheDocument(); - expect( - utils.getByText('This integration is shared by multiple agent policies.') - ).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.queryAllByText(/is already in use by some of your agents./).length).toBe(0); }); it('When multiple agent policies are present and no agents are enrolled show additional warnings', async () => { @@ -213,18 +217,18 @@ describe.skip('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + expect(utils.queryByTestId('affectedAgentsCallOut')).not.toBeInTheDocument(); + expect(utils.getByTestId('sharedAgentPolicyCallOut').textContent).toContain( + 'This integration is shared by multiple agent policies.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.queryByText('This action will affect 5 agents.')).not.toBeInTheDocument(); - expect(utils.queryAllByText(/is already in use by some of your agents./).length).toBe(0); - expect( - utils.getByText('This integration is shared by multiple agent policies.') - ).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); }); it('When agentless should show a different set of warnings', async () => { @@ -246,16 +250,19 @@ describe.skip('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + expect(utils.getByTestId('affectedAgentsCallOut').textContent).not.toContain( + 'This action will affect 5 agents.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); + expect(utils.getByTestId('confirmModalTitleText').textContent).toContain( + 'about to delete an integration' + ); }); - // utils.debug(); - expect(utils.queryByText('This action will affect 5 agents.')).not.toBeInTheDocument(); - expect(utils.getByText(/about to delete an integration/)).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.getAllByText(/integration will stop data ingestion./).length).toBe(1); }); }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index f12c4cf371ed5..70e7d77636fcc 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -247,6 +247,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ defaultMessage="This integration is shared by multiple agent policies." /> } + data-test-subj="sharedAgentPolicyCallOut" /> @@ -261,6 +262,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ <> { afterEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/fleet/server/constants/index.ts b/x-pack/plugins/fleet/server/constants/index.ts index 48de05c0b635d..ecb889a1fcae0 100644 --- a/x-pack/plugins/fleet/server/constants/index.ts +++ b/x-pack/plugins/fleet/server/constants/index.ts @@ -124,3 +124,4 @@ export { export { FILE_STORAGE_DATA_AGENT_INDEX } from './fleet_es_assets'; export { FILE_STORAGE_METADATA_AGENT_INDEX } from './fleet_es_assets'; export * from '../../common/constants/mappings'; +export * from './max_concurrency_constants'; diff --git a/x-pack/plugins/fleet/server/constants/max_concurrency_constants.ts b/x-pack/plugins/fleet/server/constants/max_concurrency_constants.ts new file mode 100644 index 0000000000000..1253d8b06e421 --- /dev/null +++ b/x-pack/plugins/fleet/server/constants/max_concurrency_constants.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Constants used across the code to limit concurrency of pMap operations +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS = 50; +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 = 20; +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10 = 10; +export const MAX_CONCURRENT_DATASTREAM_OPERATIONS = 50; +export const MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS = 20; +export const MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS = 10; +export const MAX_CONCURRENT_PACKAGE_ASSETS = 5; +export const MAX_CONCURRENT_CREATE_ACTIONS = 50; +export const MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS = 50; +export const MAX_CONCURRENT_ILM_POLICIES_OPERATIONS = 50; +export const MAX_CONCURRENT_PIPELINES_DELETIONS = 50; +export const MAX_CONCURRENT_ML_MODELS_OPERATIONS = 50; +export const MAX_CONCURRENT_COMPONENT_TEMPLATES = 50; +export const MAX_CONCURRENT_TRANSFORMS_OPERATIONS = 20; +export const MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS = 50; +export const MAX_CONCURRENT_ES_ASSETS_OPERATIONS = 50; +export const MAX_CONCURRENT_AGENT_FILES_UPLOADS = 50; +export const MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS = 20; +export const MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES = 2; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index faa18c0cfa476..6d5587e283878 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -19,7 +19,11 @@ import { HTTPAuthorizationHeader } from '../../../common/http_authorization_head import { fullAgentPolicyToYaml } from '../../../common/services'; import { appContextService, agentPolicyService } from '../../services'; import { type AgentClient, getLatestAvailableAgentVersion } from '../../services/agents'; -import { AGENTS_PREFIX, UNPRIVILEGED_AGENT_KUERY } from '../../constants'; +import { + AGENTS_PREFIX, + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10, + UNPRIVILEGED_AGENT_KUERY, +} from '../../constants'; import type { GetAgentPoliciesRequestSchema, GetOneAgentPolicyRequestSchema, @@ -82,7 +86,7 @@ export async function populateAssignedAgentsCount( .then(({ total }) => (agentPolicy.unprivileged_agents = total)); return Promise.all([totalAgents, unprivilegedAgents]); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10 } ); } diff --git a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts index 7ed4b5bacf336..2a4ab12ad0055 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts @@ -17,6 +17,7 @@ import type { GetDataStreamsResponse } from '../../../common/types'; import { getPackageSavedObjects } from '../../services/epm/packages/get'; import type { MeteringStats } from '../../services/data_streams'; import { dataStreamService } from '../../services/data_streams'; +import { MAX_CONCURRENT_DATASTREAM_OPERATIONS } from '../../constants'; import { appContextService } from '../../services'; import { getDataStreamsQueryMetadata } from './get_data_streams_query_metadata'; @@ -233,7 +234,7 @@ export const getListHandler: RequestHandler = async (context, request, response) // After filtering out data streams that are missing dataset/namespace/type/package fields body.data_streams = ( await pMap(dataStreamNames, (dataStreamName) => queryDataStreamInfo(dataStreamName), { - concurrency: 50, + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, }) ) .filter(({ dataset, namespace, type }) => dataset && namespace && type) diff --git a/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts b/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts index 2d63b357347db..880b042de4350 100644 --- a/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts +++ b/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts @@ -31,6 +31,7 @@ import type { DownloadSource, } from '../../types'; import { agentPolicyService } from '../../services'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; async function bumpRelatedPolicies( soClient: SavedObjectsClientContract, @@ -49,7 +50,7 @@ async function bumpRelatedPolicies( outputs, (output) => agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); await pMap( @@ -57,7 +58,7 @@ async function bumpRelatedPolicies( (fleetServerHost) => agentPolicyService.bumpAllAgentPoliciesForFleetServerHosts(esClient, fleetServerHost.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); @@ -66,7 +67,7 @@ async function bumpRelatedPolicies( (downloadSource) => agentPolicyService.bumpAllAgentPoliciesForDownloadSource(esClient, downloadSource.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md b/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md new file mode 100644 index 0000000000000..403ad148df23b --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md @@ -0,0 +1,33 @@ +## Agent policy SO changes + +When making changes to agent policy SO, the changes are not automatically deployed to agents. To trigger an agent policy bump, add a new model version to the agent policy SO type with a revision increase. + +``` + '2': { + changes: [ + { + type: 'data_backfill', + backfillFn: (doc) => { + return { attributes: { ...doc.attributes, revision: doc.attributes.revision + 1 } }; + }, + }, + ], + }, +``` + +## Package policy SO changes + +Similarly, package policy SO changes do not automatically trigger a redeploy of agent policies using them. To trigger an agent policy bump using package policies, add a new model version to the package policy SO type with `bump_agent_policy_revision: true`. + +``` + '2': { + changes: [ + { + type: 'data_backfill', + backfillFn: (doc) => { + return { attributes: { ...doc.attributes, bump_agent_policy_revision: true } }; + }, + }, + ], + }, +``` \ No newline at end of file diff --git a/x-pack/plugins/fleet/server/saved_objects/index.test.ts b/x-pack/plugins/fleet/server/saved_objects/index.test.ts new file mode 100644 index 0000000000000..636992dd70fe4 --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/index.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import _ from 'lodash'; + +import { getSavedObjectTypes } from '.'; + +describe('space aware models', () => { + it('should have the same mappings for space and non-space aware agent policies', () => { + const soTypes = getSavedObjectTypes(); + + const legacyMappings = _.omit( + soTypes['ingest-agent-policies'].mappings, + 'properties.monitoring_diagnostics', + 'properties.monitoring_http', + 'properties.monitoring_pprof_enabled' + ); + + expect(legacyMappings).toEqual(soTypes['fleet-agent-policies'].mappings); + }); + it('should have the same mappings for space and non-space aware package policies', () => { + const soTypes = getSavedObjectTypes(); + + expect(soTypes['ingest-package-policies'].mappings).toEqual( + soTypes['fleet-package-policies'].mappings + ); + }); +}); diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 0f196686a4719..2dfdf333fd72d 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -214,6 +214,7 @@ export const getSavedObjectTypes = ( importableAndExportable: false, }, mappings: { + dynamic: false, properties: { name: { type: 'keyword' }, schema_version: { type: 'version' }, @@ -305,6 +306,14 @@ export const getSavedObjectTypes = ( }, ], }, + '5': { + changes: [ + { + type: 'mappings_addition', + addedMappings: {}, + }, + ], + }, }, }, [AGENT_POLICY_SAVED_OBJECT_TYPE]: { @@ -316,6 +325,7 @@ export const getSavedObjectTypes = ( importableAndExportable: false, }, mappings: { + dynamic: false, properties: { name: { type: 'keyword' }, schema_version: { type: 'version' }, @@ -350,6 +360,16 @@ export const getSavedObjectTypes = ( global_data_tags: { type: 'flattened', index: false }, }, }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_addition', + addedMappings: {}, + }, + ], + }, + }, }, [OUTPUT_SAVED_OBJECT_TYPE]: { name: OUTPUT_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 21614d2a97481..eed9b058ad03f 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -97,6 +97,11 @@ import type { FullAgentConfigMap } from '../../common/types/models/agent_cm'; import { fullAgentConfigMapToYaml } from '../../common/services/agent_cm_to_yaml'; +import { + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, +} from '../constants'; + import { appContextService } from '.'; import { mapAgentPolicySavedObjectToAgentPolicy } from './agent_policies/utils'; @@ -550,7 +555,7 @@ class AgentPolicyService { } return agentPolicy; }, - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); const result = agentPolicies.filter( @@ -657,7 +662,7 @@ class AgentPolicyService { return agentPolicy; }, - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); } @@ -955,7 +960,7 @@ class AgentPolicyService { ); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); await pMap( @@ -970,7 +975,7 @@ class AgentPolicyService { }); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1014,7 +1019,7 @@ class AgentPolicyService { } ), { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1083,7 +1088,7 @@ class AgentPolicyService { this.triggerAgentPolicyUpdatedEvent(esClient, 'updated', policy.id, { spaceId: policy.namespaces?.[0], }), - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); } @@ -1352,7 +1357,7 @@ class AgentPolicyService { agentPolicy: agentPolicies?.find((policy) => policy.id === agentPolicyId), }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); @@ -1423,27 +1428,29 @@ class AgentPolicyService { ); } - await Promise.all( - fleetServerPolicies - .filter((fleetServerPolicy) => { - const policy = policiesMap[fleetServerPolicy.policy_id]; - return ( - !policy.schema_version || lt(policy.schema_version, FLEET_AGENT_POLICIES_SCHEMA_VERSION) - ); - }) - .map((fleetServerPolicy) => - // There are some potential performance concerns around using `agentPolicyService.update` in this context. - // This could potentially be a bottleneck in environments with several thousand agent policies being deployed here. - agentPolicyService.update( - soClient, - esClient, - fleetServerPolicy.policy_id, - { - schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, - }, - { force: true } - ) - ) + const filteredFleetServerPolicies = fleetServerPolicies.filter((fleetServerPolicy) => { + const policy = policiesMap[fleetServerPolicy.policy_id]; + return ( + !policy.schema_version || lt(policy.schema_version, FLEET_AGENT_POLICIES_SCHEMA_VERSION) + ); + }); + await pMap( + filteredFleetServerPolicies, + (fleetServerPolicy) => + // There are some potential performance concerns around using `agentPolicyService.update` in this context. + // This could potentially be a bottleneck in environments with several thousand agent policies being deployed here. + agentPolicyService.update( + soClient, + esClient, + fleetServerPolicy.policy_id, + { + schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, + }, + { force: true } + ), + { + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + } ); } @@ -1589,7 +1596,7 @@ class AgentPolicyService { } ), { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1890,7 +1897,7 @@ class AgentPolicyService { return { integrationPolicyName: pkgPolicy?.name, id: pkgPolicy?.output_id ?? '' }; }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -1923,7 +1930,7 @@ class AgentPolicyService { return { agentPolicyId: agentPolicy.id, ...output }; }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); return allOutputs; diff --git a/x-pack/plugins/fleet/server/services/agents/actions.ts b/x-pack/plugins/fleet/server/services/agents/actions.ts index f0dcd9a1ac62d..f2faf26fd96af 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import apm from 'elastic-apm-node'; +import pMap from 'p-map'; import { partition } from 'lodash'; @@ -33,6 +34,8 @@ import { getAgentIdsForAgentPolicies } from '../agent_policies/agent_policies_to import { getCurrentNamespace } from '../spaces/get_current_namespace'; import { addNamespaceFilteringToQuery } from '../spaces/query_namespaces_filtering'; +import { MAX_CONCURRENT_CREATE_ACTIONS } from '../../constants'; + import { bulkUpdateAgents } from './crud'; const ONE_MONTH_IN_MS = 2592000000; @@ -110,40 +113,47 @@ export async function bulkCreateAgentActions( } const messageSigningService = appContextService.getMessageSigningService(); - await esClient.bulk({ - index: AGENT_ACTIONS_INDEX, - body: await Promise.all( - actions.flatMap(async (action) => { - const body: FleetServerAgentAction = { - '@timestamp': new Date().toISOString(), - expiration: action.expiration ?? new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(), - start_time: action.start_time, - rollout_duration_seconds: action.rollout_duration_seconds, - agents: action.agents, - action_id: action.id, - data: action.data, - type: action.type, - traceparent: apm.currentTraceparent, - }; - if (SIGNED_ACTIONS.has(action.type) && messageSigningService) { - const signedBody = await messageSigningService.sign(body); - body.signed = { - data: signedBody.data.toString('base64'), - signature: signedBody.signature, - }; - } + const fleetServerAgentActions = await pMap( + actions, + async (action) => { + const body: FleetServerAgentAction = { + '@timestamp': new Date().toISOString(), + expiration: action.expiration ?? new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(), + start_time: action.start_time, + rollout_duration_seconds: action.rollout_duration_seconds, + agents: action.agents, + action_id: action.id, + data: action.data, + type: action.type, + traceparent: apm.currentTraceparent, + }; + + if (SIGNED_ACTIONS.has(action.type) && messageSigningService) { + const signedBody = await messageSigningService.sign(body); + body.signed = { + data: signedBody.data.toString('base64'), + signature: signedBody.signature, + }; + } - return [ - { - create: { - _id: action.id, - }, + return [ + { + create: { + _id: action.id, }, - body, - ]; - }) - ), + }, + body, + ].flat(); + }, + { + concurrency: MAX_CONCURRENT_CREATE_ACTIONS, + } + ); + + await esClient.bulk({ + index: AGENT_ACTIONS_INDEX, + body: fleetServerAgentActions, }); for (const action of actions) { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts index 6a14c1c301aa8..eafda9a99e4fc 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import { ElasticsearchAssetType, @@ -18,6 +19,8 @@ import { getAssetFromAssetsMap } from '../../archive'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS } from '../../../../constants'; + import { deleteIlms } from './remove'; interface IlmInstallation { @@ -111,11 +114,15 @@ export const installIlmForDataStream = async ( } ); - const installationPromises = ilmInstallations.map(async (ilmInstallation) => { - return handleIlmInstall({ esClient, ilmInstallation, logger }); - }); - - installedIlms = await Promise.all(installationPromises).then((results) => results.flat()); + installedIlms = await pMap( + ilmInstallations, + async (ilmInstallation) => { + return handleIlmInstall({ esClient, ilmInstallation, logger }); + }, + { + concurrency: MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS, + } + ).then((results) => results.flat()); } return { installedIlms, esReferences }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts index 331088d195d0b..b8f4849934757 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts @@ -7,9 +7,17 @@ import type { ElasticsearchClient } from '@kbn/core/server'; +import pMap from 'p-map'; + +import { appContextService } from '../../../app_context'; +import { MAX_CONCURRENT_ILM_POLICIES_OPERATIONS } from '../../../../constants'; + export const deleteIlms = async (esClient: ElasticsearchClient, ilmPolicyIds: string[]) => { - await Promise.all( - ilmPolicyIds.map(async (ilmPolicyId) => { + const logger = appContextService.getLogger(); + + await pMap( + ilmPolicyIds, + async (ilmPolicyId) => { await esClient.transport.request( { method: 'DELETE', @@ -19,6 +27,10 @@ export const deleteIlms = async (esClient: ElasticsearchClient, ilmPolicyIds: st ignore: [404, 400], } ); - }) + logger.debug(`Deleted ilm policy with id: ${ilmPolicyId}`); + }, + { + concurrency: MAX_CONCURRENT_ILM_POLICIES_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index 6596650a94c53..1203ec02ba9ac 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import type { EsAssetReference } from '../../../../types'; @@ -16,6 +17,7 @@ import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; import { PackageInvalidArchiveError } from '../../../../errors'; import type { PackageInstallContext } from '../../../../../common/types'; +import { MAX_CONCURRENT_ILM_POLICIES_OPERATIONS } from '../../../../constants'; export async function installILMPolicy( packageInstallContext: PackageInstallContext, @@ -48,8 +50,9 @@ export async function installILMPolicy( })), }); - await Promise.all( - ilmPolicies.map(async (policy) => { + await pMap( + ilmPolicies, + async (policy) => { try { await retryTransientEsErrors( () => @@ -63,7 +66,10 @@ export async function installILMPolicy( } catch (err) { throw new PackageInvalidArchiveError(`Couldn't install ilm policies: ${err.message}`); } - }) + }, + { + concurrency: MAX_CONCURRENT_ILM_POLICIES_OPERATIONS, + } ); return esReferences; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts index aab876652756c..242365d5cc214 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts @@ -7,11 +7,14 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; + import { appContextService } from '../../..'; import { ElasticsearchAssetType } from '../../../../types'; import { FleetError } from '../../../../errors'; import type { EsAssetReference } from '../../../../../common/types'; import { updateEsAssetReferences } from '../../packages/es_assets_reference'; +import { MAX_CONCURRENT_PIPELINES_DELETIONS } from '../../../../constants'; export const deletePreviousPipelines = async ( esClient: ElasticsearchClient, @@ -26,10 +29,15 @@ export const deletePreviousPipelines = async ( type === ElasticsearchAssetType.ingestPipeline && id.includes(previousPkgVersion) ); try { - await Promise.all( - installedPipelines.map(({ type, id }) => { + await pMap( + installedPipelines, + ({ type, id }) => { + logger.debug(`Deleting pipeline with id: ${id}`); return deletePipeline(esClient, id); - }) + }, + { + concurrency: MAX_CONCURRENT_PIPELINES_DELETIONS, + } ); } catch (e) { logger.error(e); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts index 3abd19bd8035e..7852787da0d76 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts @@ -7,17 +7,24 @@ import type { ElasticsearchClient } from '@kbn/core/server'; +import pMap from 'p-map'; + import { appContextService } from '../../../app_context'; +import { MAX_CONCURRENT_ML_MODELS_OPERATIONS } from '../../../../constants'; export const deleteMlModel = async (esClient: ElasticsearchClient, mlModelIds: string[]) => { const logger = appContextService.getLogger(); if (mlModelIds.length) { logger.info(`Deleting currently installed ml model ids ${mlModelIds}`); } - await Promise.all( - mlModelIds.map(async (modelId) => { + await pMap( + mlModelIds, + async (modelId) => { await esClient.ml.deleteTrainedModel({ model_id: modelId }, { ignore: [404] }); logger.info(`Deleted: ${modelId}`); - }) + }, + { + concurrency: MAX_CONCURRENT_ML_MODELS_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts index 3b4b74cf772e5..f735e8638b583 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts @@ -124,12 +124,13 @@ describe('EPM index template install', () => { const packageTemplate = componentTemplates['metrics-package.dataset@package'].template; - if (!('mappings' in packageTemplate)) { + if (!('settings' in packageTemplate)) { throw new Error('no mappings on package template'); } - expect(packageTemplate.mappings).toHaveProperty('_source'); - expect(packageTemplate.mappings._source).toEqual({ mode: 'synthetic' }); + expect(packageTemplate.settings?.index?.mapping).toHaveProperty('source'); + // @ts-expect-error esclient mapping out-of-date + expect(packageTemplate.settings?.index?.mapping?.source).toEqual({ mode: 'synthetic' }); }); it('tests prepareTemplate to set source mode to synthetics if index_mode:time_series', async () => { @@ -154,12 +155,13 @@ describe('EPM index template install', () => { const packageTemplate = componentTemplates['metrics-package.dataset@package'].template; - if (!('mappings' in packageTemplate)) { - throw new Error('no mappings on package template'); + if (!('settings' in packageTemplate)) { + throw new Error('no settings on package template'); } - expect(packageTemplate.mappings).toHaveProperty('_source'); - expect(packageTemplate.mappings._source).toEqual({ mode: 'synthetic' }); + expect(packageTemplate.settings?.index?.mapping).toHaveProperty('source'); + // @ts-expect-error esclient mapping out-of-date + expect(packageTemplate.settings?.index?.mapping?.source).toEqual({ mode: 'synthetic' }); }); it('tests prepareTemplate to not set source mode to synthetics if index_mode:time_series and user disabled synthetic', async () => { @@ -193,11 +195,11 @@ describe('EPM index template install', () => { const packageTemplate = componentTemplates['metrics-package.dataset@package'].template; - if (!('mappings' in packageTemplate)) { - throw new Error('no mappings on package template'); + if (!('settings' in packageTemplate)) { + throw new Error('no settings on package template'); } - expect(packageTemplate.mappings).not.toHaveProperty('_source'); + expect(packageTemplate.settings?.index?.mapping).not.toHaveProperty('source'); }); it('tests prepareTemplate to not set source mode to synthetics if specified but user disabled it', async () => { @@ -231,11 +233,11 @@ describe('EPM index template install', () => { const packageTemplate = componentTemplates['metrics-package.dataset@package'].template; - if (!('mappings' in packageTemplate)) { - throw new Error('no mappings on package template'); + if (!('settings' in packageTemplate)) { + throw new Error('no settings on package template'); } - expect(packageTemplate.mappings).not.toHaveProperty('_source'); + expect(packageTemplate.settings?.index?.mapping).not.toHaveProperty('source'); }); it('tests prepareTemplate to set index_mode time series if index_mode:time_series', async () => { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index 2a17768ac1f9c..f17a05a6837aa 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -8,6 +8,7 @@ import { merge, concat, uniqBy, omit } from 'lodash'; import Boom from '@hapi/boom'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import pMap from 'p-map'; import type { IndicesCreateRequest, @@ -38,6 +39,7 @@ import { PACKAGE_TEMPLATE_SUFFIX, USER_SETTINGS_TEMPLATE_SUFFIX, STACK_COMPONENT_TEMPLATES, + MAX_CONCURRENT_COMPONENT_TEMPLATES, } from '../../../../constants'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; @@ -103,15 +105,18 @@ export const prepareToInstallTemplates = ( await installPreBuiltComponentTemplates(packageInstallContext, esClient, logger); await installPreBuiltTemplates(packageInstallContext, esClient, logger); - await Promise.all( - templates.map((template) => + await pMap( + templates, + (template) => installComponentAndIndexTemplateForDataStream({ esClient, logger, componentTemplates: template.componentTemplates, indexTemplate: template.indexTemplate, - }) - ) + }), + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); return templates.map((template) => template.indexTemplate); @@ -125,32 +130,37 @@ const installPreBuiltTemplates = async ( logger: Logger ) => { const templatePaths = packageInstallContext.paths.filter((path) => isTemplate(path)); - const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = getPathParts(path); - const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse( - getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') - ); - - const esClientParams = { name: templateName, body: content }; - const esClientRequestOptions = { ignore: [404] }; - - if (Object.hasOwn(content, 'template') || Object.hasOwn(content, 'composed_of')) { - // Template is v2 - return retryTransientEsErrors( - () => esClient.indices.putIndexTemplate(esClientParams, esClientRequestOptions), - { logger } - ); - } else { - // template is V1 - return retryTransientEsErrors( - () => esClient.indices.putTemplate(esClientParams, esClientRequestOptions), - { logger } - ); - } - }); try { - return await Promise.all(templateInstallPromises); + await pMap( + templatePaths, + async (path) => { + const { file } = getPathParts(path); + const templateName = file.substr(0, file.lastIndexOf('.')); + const content = JSON.parse( + getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') + ); + + const esClientParams = { name: templateName, body: content }; + const esClientRequestOptions = { ignore: [404] }; + + if (Object.hasOwn(content, 'template') || Object.hasOwn(content, 'composed_of')) { + // Template is v2 + return retryTransientEsErrors( + () => esClient.indices.putIndexTemplate(esClientParams, esClientRequestOptions), + { logger } + ); + } else { + // template is V1 + return retryTransientEsErrors( + () => esClient.indices.putTemplate(esClientParams, esClientRequestOptions), + { logger } + ); + } + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } + ); } catch (e) { throw new Boom.Boom(`Error installing prebuilt index templates ${e.message}`, { statusCode: 400, @@ -164,26 +174,30 @@ const installPreBuiltComponentTemplates = async ( logger: Logger ) => { const templatePaths = packageInstallContext.paths.filter((path) => isComponentTemplate(path)); - const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = getPathParts(path); - const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse( - getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') - ); - - const esClientParams = { - name: templateName, - body: content, - }; - - return retryTransientEsErrors( - () => esClient.cluster.putComponentTemplate(esClientParams, { ignore: [404] }), - { logger } - ); - }); - try { - return await Promise.all(templateInstallPromises); + await pMap( + templatePaths, + async (path) => { + const { file } = getPathParts(path); + const templateName = file.substr(0, file.lastIndexOf('.')); + const content = JSON.parse( + getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') + ); + + const esClientParams = { + name: templateName, + body: content, + }; + + return retryTransientEsErrors( + () => esClient.cluster.putComponentTemplate(esClientParams, { ignore: [404] }), + { logger } + ); + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } + ); } catch (e) { throw new Boom.Boom(`Error installing prebuilt component templates ${e.message}`, { statusCode: 400, @@ -395,6 +409,14 @@ export function buildComponentTemplates(params: { templateSettings.index?.mapping?.total_fields?.limit ), }, + ...(templateSettings.index?.mapping?.source || sourceModeSynthetic + ? { + source: { + ...templateSettings.index?.mapping?.source, + ...(sourceModeSynthetic ? { mode: 'synthetic' } : {}), + }, + } + : {}), }, }, }, @@ -404,15 +426,7 @@ export function buildComponentTemplates(params: { ? { runtime: mappingsRuntimeFields } : {}), dynamic_templates: mappingsDynamicTemplates.length ? mappingsDynamicTemplates : undefined, - ...omit(indexTemplateMappings, 'properties', 'dynamic_templates', '_source', 'runtime'), - ...(indexTemplateMappings?._source || sourceModeSynthetic - ? { - _source: { - ...indexTemplateMappings?._source, - ...(sourceModeSynthetic ? { mode: 'synthetic' } : {}), - }, - } - : {}), + ...omit(indexTemplateMappings, 'properties', 'dynamic_templates', 'runtime'), }, ...(lifecycle ? { lifecycle } : {}), }, @@ -450,8 +464,9 @@ async function installDataStreamComponentTemplates({ logger: Logger; componentTemplates: TemplateMap; }) { - await Promise.all( - Object.entries(componentTemplates).map(async ([name, body]) => { + await pMap( + Object.entries(componentTemplates), + async ([name, body]) => { // @custom component template should be lazily created by user if (isUserSettingsTemplate(name)) { return; @@ -459,7 +474,10 @@ async function installDataStreamComponentTemplates({ const { clusterPromise } = putComponentTemplate(esClient, logger, { body, name }); return clusterPromise; - }) + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); } @@ -467,10 +485,12 @@ export async function ensureDefaultComponentTemplates( esClient: ElasticsearchClient, logger: Logger ) { - return Promise.all( - FLEET_COMPONENT_TEMPLATES.map(({ name, body }) => - ensureComponentTemplate(esClient, logger, name, body) - ) + return await pMap( + FLEET_COMPONENT_TEMPLATES, + ({ name, body }) => ensureComponentTemplate(esClient, logger, name, body), + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); } diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index dbc93e35c8218..9fc5383902ff3 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -2105,6 +2105,57 @@ describe('EPM template', () => { }) ); }); + it('should rollover on mapper exception with subobjects in reason', async () => { + const esClient = elasticsearchServiceMock.createElasticsearchClient(); + esClient.indices.getDataStream.mockResponse({ + data_streams: [{ name: 'test.prefix1-default' }], + } as any); + esClient.indices.get.mockResponse({ + 'test.prefix1-default': { + mappings: {}, + }, + } as any); + esClient.indices.simulateTemplate.mockResponse({ + template: { + settings: { index: {} }, + mappings: {}, + }, + } as any); + esClient.indices.putMapping.mockImplementation(() => { + throw new errors.ResponseError({ + body: { + error: { + type: 'mapper_exception', + reason: + "the [subobjects] parameter can't be updated for the object mapping [okta.debug_context.debug_data]", + }, + }, + } as any); + }); + + const logger = loggerMock.create(); + await updateCurrentWriteIndices(esClient, logger, [ + { + templateName: 'test', + indexTemplate: { + index_patterns: ['test.*-*'], + template: { + settings: { index: {} }, + mappings: {}, + }, + } as any, + }, + ]); + + expect(esClient.transport.request).toHaveBeenCalledWith( + expect.objectContaining({ + path: '/test.prefix1-default/_rollover', + querystring: { + lazy: true, + }, + }) + ); + }); it('should skip rollover on expected error when flag is on', async () => { const esClient = elasticsearchServiceMock.createElasticsearchClient(); esClient.indices.getDataStream.mockResponse({ diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index bb38480fd66b7..d44cd57a2c5ba 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -19,6 +19,7 @@ import { FLEET_EVENT_INGESTED_COMPONENT_TEMPLATE_NAME, STACK_COMPONENT_TEMPLATE_LOGS_MAPPINGS, } from '../../../../constants/fleet_es_assets'; +import { MAX_CONCURRENT_DATASTREAM_OPERATIONS } from '../../../../constants'; import type { Field, Fields } from '../../fields/field'; import type { @@ -931,10 +932,15 @@ const queryDataStreamsFromTemplates = async ( esClient: ElasticsearchClient, templates: IndexTemplateEntry[] ): Promise => { - const dataStreamPromises = templates.map((template) => { - return getDataStreams(esClient, template); - }); - const dataStreamObjects = await Promise.all(dataStreamPromises); + const dataStreamObjects = await pMap( + templates, + (template) => { + return getDataStreams(esClient, template); + }, + { + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, + } + ); return dataStreamObjects.filter(isCurrentDataStream).flat(); }; @@ -997,8 +1003,7 @@ const updateAllDataStreams = async ( }); }, { - // Limit concurrent putMapping/rollover requests to avoid overwhelming ES cluster - concurrency: 20, + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, } ); }; @@ -1026,8 +1031,8 @@ const updateExistingDataStream = async ({ const existingDsConfig = Object.values(existingDs); const currentBackingIndexConfig = existingDsConfig.at(-1); const currentIndexMode = currentBackingIndexConfig?.settings?.index?.mode; - // @ts-expect-error Property 'mode' does not exist on type 'MappingSourceField' - const currentSourceType = currentBackingIndexConfig.mappings?._source?.mode; + // @ts-expect-error Property 'source.mode' does not exist on type 'IndicesMappingLimitSettings' + const currentSourceType = currentBackingIndexConfig?.settings?.index?.mapping?.source?.mode; let settings: IndicesIndexSettings; let mappings: MappingTypeMapping = {}; @@ -1079,6 +1084,10 @@ const updateExistingDataStream = async ({ // if update fails, rollover data stream and bail out } catch (err) { + subobjectsFieldChanged = + subobjectsFieldChanged || + (err.body?.error?.type === 'mapper_exception' && + err.body?.error?.reason?.includes('subobjects')); if ( (isResponseError(err) && err.statusCode === 400 && @@ -1132,7 +1141,7 @@ const updateExistingDataStream = async ({ // Trigger a rollover if the index mode or source type has changed if ( currentIndexMode !== settings?.index?.mode || - currentSourceType !== mappings?._source?.mode || + currentSourceType !== settings?.index?.source?.mode || dynamicDimensionMappingsChanged ) { if (options?.skipDataStreamRollover === true) { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index cbdde6feee64c..85ae293455c9e 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -10,6 +10,7 @@ import { errors } from '@elastic/elasticsearch'; import { load } from 'js-yaml'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { uniqBy } from 'lodash'; +import pMap from 'p-map'; import type { HTTPAuthorizationHeader } from '../../../../../common/http_authorization_header'; @@ -44,6 +45,8 @@ import { getInstallation } from '../../packages'; import { retryTransientEsErrors } from '../retry'; import { isUserSettingsTemplate } from '../template/utils'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; + import { deleteTransforms } from './remove'; import { getDestinationIndexAliases } from './transform_utils'; import { loadMappingForTransform } from './mappings'; @@ -573,17 +576,21 @@ const installTransformsAssets = async ( } } else { // Else, create & start all the transforms at once for speed - const transformsPromises = transforms.map(async (transform) => { - return handleTransformInstall({ - esClient, - logger, - transform, - startTransform: transformsSpecifications.get(transform.transformModuleId)?.get('start'), - secondaryAuth: transform.runAsKibanaSystem !== false ? undefined : secondaryAuth, - }); - }); - - installedTransforms = await Promise.all(transformsPromises).then((results) => results.flat()); + installedTransforms = await pMap( + transforms, + async (transform) => { + return handleTransformInstall({ + esClient, + logger, + transform, + startTransform: transformsSpecifications.get(transform.transformModuleId)?.get('start'), + secondaryAuth: transform.runAsKibanaSystem !== false ? undefined : secondaryAuth, + }); + }, + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } + ).then((results) => results.flat()); } // If user does not have sufficient permissions to start the transforms, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts index d1a492cb213a9..8d53a952608fa 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts @@ -10,6 +10,7 @@ import type { Logger } from '@kbn/logging'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { sortBy, uniqBy } from 'lodash'; +import pMap from 'p-map'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { ErrorResponseBase } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -19,6 +20,7 @@ import type { Installation } from '../../../../../common'; import { ElasticsearchAssetType, PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; interface FleetTransformMetadata { fleet_transform_version?: string; @@ -119,8 +121,9 @@ export async function handleTransformReauthorizeAndStart({ ); } - const transformInfos = await Promise.all( - transforms.map(({ transformId }) => + const transformInfos = await pMap( + transforms, + ({ transformId }) => retryTransientEsErrors( () => esClient.transform.getTransform( @@ -130,8 +133,10 @@ export async function handleTransformReauthorizeAndStart({ { ...(secondaryAuth ? secondaryAuth : {}), ignore: [404] } ), { logger, additionalResponseStatuses: [400] } - ) - ) + ), + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } ); const transformsMetadata: FleetTransformMetadata[] = transformInfos @@ -168,17 +173,20 @@ export async function handleTransformReauthorizeAndStart({ } } else { // Else, create & start all the transforms at once for speed - const transformsPromises = transformsMetadata.map(async ({ transformId, ...meta }) => { - return await reauthorizeAndStartTransform({ - esClient, - logger, - transformId, - secondaryAuth, - meta: { ...meta, last_authorized_by: username }, - }); - }); - - authorizedTransforms = await Promise.all(transformsPromises).then((results) => results.flat()); + authorizedTransforms = await pMap( + transformsMetadata, + async ({ transformId, ...meta }) => + reauthorizeAndStartTransform({ + esClient, + logger, + transformId, + secondaryAuth, + meta: { ...meta, last_authorized_by: username }, + }), + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } + ).then((results) => results.flat()); } const so = await savedObjectsClient.get(PACKAGES_SAVED_OBJECT_TYPE, pkgName); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts index 4149d15899166..8a2d5cd13c59d 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import type { SecondaryAuthorizationHeader } from '../../../../../common/types/models/transform_api_key'; import { ElasticsearchAssetType } from '../../../../types'; @@ -14,6 +15,7 @@ import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; import { appContextService } from '../../../app_context'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; export const stopTransforms = async (transformIds: string[], esClient: ElasticsearchClient) => { for (const transformId of transformIds) { @@ -34,8 +36,10 @@ export const deleteTransforms = async ( if (transformIds.length) { logger.info(`Deleting currently installed transform ids ${transformIds}`); } - await Promise.all( - transformIds.map(async (transformId) => { + + await pMap( + transformIds, + async (transformId) => { await stopTransforms([transformId], esClient); await retryTransientEsErrors(() => esClient.transform.deleteTransform( @@ -48,7 +52,10 @@ export const deleteTransforms = async ( ) ); logger.info(`Deleted: ${transformId}`); - }) + }, + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts index 3ae1c4a6cffba..3ecdfe02319a9 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts @@ -6,10 +6,12 @@ */ import type { SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import { dataTypes, installationStatuses } from '../../../../../common/constants'; import { appContextService } from '../../..'; import { getPackageSavedObjects } from '../../packages/get'; +import { MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS } from '../../../../constants'; const INDEX_PATTERN_SAVED_OBJECT_TYPE = 'index-pattern'; export const indexPatternTypes = [dataTypes.Logs, dataTypes.Metrics]; @@ -72,9 +74,9 @@ export async function removeUnusedIndexPatterns(savedObjectsClient: SavedObjects // eslint-disable-next-line @typescript-eslint/naming-convention const idsToDelete = resolvedObjects.map(({ saved_object }) => saved_object.id); - - return Promise.all( - idsToDelete.map(async (id) => { + await pMap( + idsToDelete, + async (id) => { try { logger.debug(`deleting index pattern ${id}`); await savedObjectsClient.delete(INDEX_PATTERN_SAVED_OBJECT_TYPE, id); @@ -83,6 +85,9 @@ export async function removeUnusedIndexPatterns(savedObjectsClient: SavedObjects logger.debug(`Non fatal error encountered deleting index pattern ${id} : ${err}`); } return; - }) + }, + { + concurrency: MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS, + } ); } diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts b/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts index eeaa80b0c9449..e72b218ab1fcc 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts @@ -17,6 +17,7 @@ const createClientMock = (): jest.Mocked => ({ fetchFindLatestPackage: jest.fn(), readBundledPackage: jest.fn(), getAgentPolicyConfigYAML: jest.fn(), + getLatestPackageInfo: jest.fn(), getPackage: jest.fn(), getPackageFieldsMetadata: jest.fn(), getPackages: jest.fn(), diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.test.ts b/x-pack/plugins/fleet/server/services/epm/package_service.test.ts index 479d355c00e68..ea7586b9ebd78 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.test.ts @@ -43,6 +43,7 @@ const testKeys = [ 'getInstallation', 'ensureInstalledPackage', 'fetchFindLatestPackage', + 'getLatestPackageInfo', 'getPackage', 'getPackageFieldsMetadata', 'reinstallEsAssets', @@ -112,6 +113,23 @@ function getTest( }; break; case testKeys[3]: + test = { + method: mocks.packageClient.getLatestPackageInfo.bind(mocks.packageClient), + args: ['package name'], + spy: jest.spyOn(epmPackagesGet, 'getPackageInfo'), + spyArgs: [ + { + pkgName: 'package name', + pkgVersion: '', + savedObjectsClient: mocks.soClient, + prerelease: undefined, + }, + ], + spyResponse: { name: 'getLatestPackageInfo test' }, + expectedReturnValue: { name: 'getLatestPackageInfo test' }, + }; + break; + case testKeys[4]: test = { method: mocks.packageClient.getPackage.bind(mocks.packageClient), args: ['package name', '8.0.0'], @@ -127,7 +145,7 @@ function getTest( }, }; break; - case testKeys[4]: + case testKeys[5]: test = { method: mocks.packageClient.getPackageFieldsMetadata.bind(mocks.packageClient), args: [{ packageName: 'package_name', datasetName: 'dataset_name' }], @@ -141,7 +159,7 @@ function getTest( }, }; break; - case testKeys[5]: + case testKeys[6]: const pkg: InstallablePackage = { format_version: '1.0.0', name: 'package name', @@ -187,7 +205,7 @@ function getTest( ], }; break; - case testKeys[6]: + case testKeys[7]: const bundledPackage = { name: 'package name', version: '8.0.0', diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.ts b/x-pack/plugins/fleet/server/services/epm/package_service.ts index a097db584b460..782aeffb6a85c 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.ts @@ -56,6 +56,7 @@ import { getPackages, installPackage, getTemplateInputs, + getPackageInfo, } from './packages'; import { generatePackageInfoFromArchiveBuffer } from './archive'; import { getEsPackage } from './archive/storage'; @@ -113,6 +114,11 @@ export interface PackageClient { options?: Parameters['1'] ): ReturnType; + getLatestPackageInfo( + packageName: string, + prerelease?: boolean + ): ReturnType; + getPackages(params?: { excludeInstallStatus?: false; category?: CategoryId; @@ -328,6 +334,16 @@ class PackageClientImpl implements PackageClient { return getPackageFieldsMetadata(params, options); } + public async getLatestPackageInfo(packageName: string, prerelease?: boolean) { + await this.#runPreflight(READ_PACKAGE_INFO_AUTHZ); + return getPackageInfo({ + savedObjectsClient: this.internalSoClient, + pkgName: packageName, + pkgVersion: '', + prerelease, + }); + } + public async getPackages(params?: { excludeInstallStatus?: false; category?: CategoryId; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index 2ab0856063367..5b0e3df279cdc 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -39,7 +39,10 @@ import type { PackageSpecManifest, AssetsMap, } from '../../../../common/types'; -import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; +import { + PACKAGES_SAVED_OBJECT_TYPE, + MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS, +} from '../../../constants'; import type { ArchivePackage, RegistryPackage, @@ -142,7 +145,7 @@ export async function getPackages( ); } }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ) ).filter((p): p is Installable => p !== null); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts index 84c8a8eb9e104..0557027a3c0a6 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts @@ -17,10 +17,12 @@ import { SavedObjectsUtils, SavedObjectsErrorHelpers } from '@kbn/core/server'; import minVersion from 'semver/ranges/min-version'; import { chunk } from 'lodash'; +import pMap from 'p-map'; import { updateIndexSettings } from '../elasticsearch/index/update_settings'; import { + MAX_CONCURRENT_ES_ASSETS_OPERATIONS, PACKAGE_POLICY_SAVED_OBJECT_TYPE, PACKAGES_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT, @@ -209,29 +211,36 @@ async function bulkDeleteSavedObjects( } } -export function deleteESAssets( +export const deleteESAsset = async ( + installedObject: EsAssetReference, + esClient: ElasticsearchClient +): Promise => { + const { id, type } = installedObject; + const assetType = type as AssetType; + if (assetType === ElasticsearchAssetType.ingestPipeline) { + return deletePipeline(esClient, id); + } else if (assetType === ElasticsearchAssetType.indexTemplate) { + return deleteIndexTemplate(esClient, id); + } else if (assetType === ElasticsearchAssetType.componentTemplate) { + return deleteComponentTemplate(esClient, id); + } else if (assetType === ElasticsearchAssetType.transform) { + return deleteTransforms(esClient, [id], true); + } else if (assetType === ElasticsearchAssetType.dataStreamIlmPolicy) { + return deleteIlms(esClient, [id]); + } else if (assetType === ElasticsearchAssetType.ilmPolicy) { + return deleteIlms(esClient, [id]); + } else if (assetType === ElasticsearchAssetType.mlModel) { + return deleteMlModel(esClient, [id]); + } +}; + +export const deleteESAssets = ( installedObjects: EsAssetReference[], esClient: ElasticsearchClient -): Array> { - return installedObjects.map(async ({ id, type }) => { - const assetType = type as AssetType; - if (assetType === ElasticsearchAssetType.ingestPipeline) { - return deletePipeline(esClient, id); - } else if (assetType === ElasticsearchAssetType.indexTemplate) { - return deleteIndexTemplate(esClient, id); - } else if (assetType === ElasticsearchAssetType.componentTemplate) { - return deleteComponentTemplate(esClient, id); - } else if (assetType === ElasticsearchAssetType.transform) { - return deleteTransforms(esClient, [id], true); - } else if (assetType === ElasticsearchAssetType.dataStreamIlmPolicy) { - return deleteIlms(esClient, [id]); - } else if (assetType === ElasticsearchAssetType.ilmPolicy) { - return deleteIlms(esClient, [id]); - } else if (assetType === ElasticsearchAssetType.mlModel) { - return deleteMlModel(esClient, [id]); - } - }); -} +): Array> => { + return installedObjects.map((installedObject) => deleteESAsset(installedObject, esClient)); +}; + type Tuple = [EsAssetReference[], EsAssetReference[], EsAssetReference[], EsAssetReference[]]; export const splitESAssets = (installedEs: EsAssetReference[]) => { @@ -291,16 +300,24 @@ export async function deletePrerequisiteAssets( try { // must first unset any default pipeline associated with any existing indices // by setting empty string - await Promise.all( - indexAssets.map((asset) => updateIndexSettings(esClient, asset.id, { default_pipeline: '' })) + await pMap( + indexAssets, + (asset) => updateIndexSettings(esClient, asset.id, { default_pipeline: '' }), + { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + } ); // in case transform's destination index contains any pipeline, // we should delete the transforms first - await Promise.all(deleteESAssets(transformAssets, esClient)); + await pMap(transformAssets, (transformAsset) => deleteESAsset(transformAsset, esClient), { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + }); // then delete index templates and pipelines - await Promise.all(deleteESAssets(indexTemplatesAndPipelines, esClient)); + await pMap(indexTemplatesAndPipelines, (asset) => deleteESAsset(asset, esClient), { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + }); } catch (err) { // in the rollback case, partial installs are likely, so missing assets are not an error if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { diff --git a/x-pack/plugins/fleet/server/services/files/index.ts b/x-pack/plugins/fleet/server/services/files/index.ts index c7a00ee597f62..0598155153ce6 100644 --- a/x-pack/plugins/fleet/server/services/files/index.ts +++ b/x-pack/plugins/fleet/server/services/files/index.ts @@ -8,6 +8,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import type { SearchHit, UpdateByQueryResponse } from '@elastic/elasticsearch/lib/api/types'; import type { FileStatus } from '@kbn/files-plugin/common/types'; +import pMap from 'p-map'; import { FILE_STORAGE_DATA_INDEX_PATTERN, @@ -20,6 +21,8 @@ import { getFileMetadataIndexName } from '../../../common/services'; import { ES_SEARCH_LIMIT } from '../../../common/constants'; +import { MAX_CONCURRENT_AGENT_FILES_UPLOADS } from '../../constants'; + import { parseFileStorageIndex } from './utils'; /** @@ -145,14 +148,15 @@ export async function fileIdsWithoutChunksByIndex( * @param fileIdsByIndex * @param status */ -export function updateFilesStatus( +export async function updateFilesStatus( esClient: ElasticsearchClient, abortController: AbortController | undefined, fileIdsByIndex: FileIdsByIndex, status: FileStatus ): Promise { - return Promise.all( - Object.entries(fileIdsByIndex).map(([index, fileIds]) => { + return await pMap( + Object.entries(fileIdsByIndex), + ([index, fileIds]) => { return esClient .updateByQuery( { @@ -174,6 +178,9 @@ export function updateFilesStatus( Error.captureStackTrace(err); throw err; }); - }) + }, + { + concurrency: MAX_CONCURRENT_AGENT_FILES_UPLOADS, + } ); } diff --git a/x-pack/plugins/fleet/server/services/fleet_proxies.ts b/x-pack/plugins/fleet/server/services/fleet_proxies.ts index 4cfc81db50740..e60c15577bdc2 100644 --- a/x-pack/plugins/fleet/server/services/fleet_proxies.ts +++ b/x-pack/plugins/fleet/server/services/fleet_proxies.ts @@ -13,7 +13,11 @@ import type { import { omit } from 'lodash'; import pMap from 'p-map'; -import { FLEET_PROXY_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT } from '../constants'; +import { + FLEET_PROXY_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, + MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS, +} from '../constants'; import { FleetProxyUnauthorizedError } from '../errors'; import type { DownloadSource, @@ -206,7 +210,7 @@ async function updateRelatedSavedObject( ...omit(fleetServerHost, 'id'), proxy_id: null, }), - { concurrency: 20 } + { concurrency: MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS } ); await pMap( @@ -216,7 +220,7 @@ async function updateRelatedSavedObject( ...omit(output, 'id'), proxy_id: null, } as Partial), - { concurrency: 20 } + { concurrency: MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS } ); await pMap(downloadSources, (downloadSource) => diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index ceecd29562fc9..0b30890ee566d 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -44,6 +44,7 @@ import { DEFAULT_OUTPUT_ID, OUTPUT_SAVED_OBJECT_TYPE, OUTPUT_HEALTH_DATA_STREAM, + MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS, } from '../constants'; import { SO_SEARCH_LIMIT, @@ -1165,7 +1166,7 @@ class OutputService { await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id); }, { - concurrency: 5, + concurrency: MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS, } ); } diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index eac31bb980256..32ec4c90b4319 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -100,6 +100,11 @@ import type { } from '../types'; import type { ExternalCallback } from '..'; +import { + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + MAX_CONCURRENT_PACKAGE_ASSETS, +} from '../constants'; + import { createSoFindIterable } from './utils/create_so_find_iterable'; import type { FleetAuthzRouteConfig } from './security'; @@ -178,7 +183,7 @@ async function getPkgInfoAssetsMap({ pkgInfo, }); }, - { concurrency: 5 } + { concurrency: MAX_CONCURRENT_PACKAGE_ASSETS } ); return packageInfosandAssetsMap; @@ -2211,7 +2216,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); await pMap( @@ -2231,7 +2236,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts index 03787b8e6be65..d09494e52d30b 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts @@ -22,6 +22,8 @@ import { listFleetServerHostsForProxyId } from '../fleet_server_host'; import { agentPolicyService } from '../agent_policy'; import { outputService } from '../output'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; + export function getPreconfiguredFleetProxiesFromConfig(config?: FleetConfigType) { const { proxies: fleetProxiesFromConfig } = config; @@ -107,7 +109,7 @@ async function createOrUpdatePreconfiguredFleetProxies( outputs, (output) => agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); await pMap( @@ -118,7 +120,7 @@ async function createOrUpdatePreconfiguredFleetProxies( fleetServerHost.id ), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 714b16af5bcd2..f605df4680b31 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -11,6 +11,7 @@ import utils from 'node:util'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import { isEqual } from 'lodash'; import { dump } from 'js-yaml'; +import pMap from 'p-map'; const pbkdf2Async = utils.promisify(crypto.pbkdf2); @@ -32,6 +33,8 @@ import { appContextService } from '../app_context'; import { isDifferent } from './utils'; +export const MAX_CONCURRENT_OUTPUTS_OPERATIONS = 50; + export function getPreconfiguredOutputFromConfig(config?: FleetConfigType) { const { outputs: outputsOrUndefined } = config; @@ -78,67 +81,69 @@ export async function createOrUpdatePreconfiguredOutputs( { ignoreNotFound: true } ); - await Promise.all( - outputs.map(async (output) => { - const existingOutput = existingOutputs.find((o) => o.id === output.id); + const updateOrConfigureOutput = async (output: PreconfiguredOutput) => { + const existingOutput = existingOutputs.find((o) => o.id === output.id); - const { id, config, ...outputData } = output; + const { id, config, ...outputData } = output; - const configYaml = config ? dump(config) : undefined; + const configYaml = config ? dump(config) : undefined; - const data: NewOutput = { - ...outputData, - is_preconfigured: true, - config_yaml: configYaml ?? null, - // Set value to null to update these fields on update - ca_sha256: outputData.ca_sha256 ?? null, - ca_trusted_fingerprint: outputData.ca_trusted_fingerprint ?? null, - ssl: outputData.ssl ?? null, - } as NewOutput; + const data: NewOutput = { + ...outputData, + is_preconfigured: true, + config_yaml: configYaml ?? null, + // Set value to null to update these fields on update + ca_sha256: outputData.ca_sha256 ?? null, + ca_trusted_fingerprint: outputData.ca_trusted_fingerprint ?? null, + ssl: outputData.ssl ?? null, + } as NewOutput; - if (!data.hosts || data.hosts.length === 0) { - data.hosts = outputService.getDefaultESHosts(); - } + if (!data.hosts || data.hosts.length === 0) { + data.hosts = outputService.getDefaultESHosts(); + } - const isCreate = !existingOutput; + const isCreate = !existingOutput; - // field in allow edit are not updated through preconfiguration - if (!isCreate && output.allow_edit) { - for (const key of output.allow_edit) { - // @ts-expect-error - data[key] = existingOutput[key]; - } + // field in allow edit are not updated through preconfiguration + if (!isCreate && output.allow_edit) { + for (const key of output.allow_edit) { + // @ts-expect-error + data[key] = existingOutput[key]; } + } + + const isUpdateWithNewData = + existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)); + + if (isCreate || isUpdateWithNewData) { + const secretHashes = await hashSecrets(output); - const isUpdateWithNewData = - existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)); - - if (isCreate || isUpdateWithNewData) { - const secretHashes = await hashSecrets(output); - - if (isCreate) { - logger.debug(`Creating preconfigured output ${output.id}`); - await outputService.create(soClient, esClient, data, { - id, - fromPreconfiguration: true, - secretHashes, - }); - } else if (isUpdateWithNewData) { - logger.debug(`Updating preconfigured output ${output.id}`); - await outputService.update(soClient, esClient, id, data, { - fromPreconfiguration: true, - secretHashes, - }); - // Bump revision of all policies using that output - if (outputData.is_default || outputData.is_default_monitoring) { - await agentPolicyService.bumpAllAgentPolicies(esClient); - } else { - await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, id); - } + if (isCreate) { + logger.debug(`Creating preconfigured output ${output.id}`); + await outputService.create(soClient, esClient, data, { + id, + fromPreconfiguration: true, + secretHashes, + }); + } else if (isUpdateWithNewData) { + logger.debug(`Updating preconfigured output ${output.id}`); + await outputService.update(soClient, esClient, id, data, { + fromPreconfiguration: true, + secretHashes, + }); + // Bump revision of all policies using that output + if (outputData.is_default || outputData.is_default_monitoring) { + await agentPolicyService.bumpAllAgentPolicies(esClient); + } else { + await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, id); } } - }) - ); + } + }; + + await pMap(outputs, (output) => updateOrConfigureOutput(output), { + concurrency: MAX_CONCURRENT_OUTPUTS_OPERATIONS, + }); } // Values recommended by NodeJS documentation diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts b/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts index 7e65dd665d0bd..84dbbf817d665 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts @@ -24,6 +24,8 @@ import { listEnrollmentApiKeys, deleteEnrollmentApiKey } from '../api_keys'; import type { AgentPolicy } from '../../types'; import { AgentPolicyInvalidError } from '../../errors'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; + export async function resetPreconfiguredAgentPolicies( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, @@ -83,7 +85,7 @@ async function _deleteGhostPackagePolicies( } }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -116,7 +118,7 @@ async function _deletePreconfigurationDeleteRecord( }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -167,7 +169,7 @@ async function _deleteExistingData( if (agents.length > 0) { logger.info(`Force unenrolling ${agents.length} agents`); await pMap(agents, (agent) => forceUnenrollAgent(esClient, soClient, agent.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, }); } @@ -183,7 +185,7 @@ async function _deleteExistingData( enrollmentApiKeys, (enrollmentKey) => deleteEnrollmentApiKey(esClient, enrollmentKey.id, true), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -195,7 +197,7 @@ async function _deleteExistingData( force: true, }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index ab882a013ebe3..24d655a4cae16 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -21,6 +21,8 @@ import { AUTO_UPDATE_PACKAGES, FLEET_SETUP_LOCK_TYPE } from '../../common/consta import type { PreconfigurationError } from '../../common/constants'; import type { DefaultPackagesInstallationError, FleetSetupLock } from '../../common/types'; +import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; + import { appContextService } from './app_context'; import { ensurePreconfiguredPackagesAndPolicies } from './preconfiguration'; import { @@ -359,7 +361,7 @@ export async function ensureFleetGlobalEsAssets( ); }); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ); } } diff --git a/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx b/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx index cd3317c5eb23b..ab3045ee57a08 100644 --- a/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx +++ b/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx @@ -8,6 +8,8 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import pMap from 'p-map'; +import { MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES } from '../../constants'; + const INDICES_TO_CLEAN = [ '.fleet-files-*', '.fleet-file-data-*', @@ -49,7 +51,7 @@ export async function cleanUpOldFileIndices(esClient: ElasticsearchClient, logge }); } }, - { concurrency: 2 } + { concurrency: MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES } ); await esClient.indices .deleteIndexTemplate({ diff --git a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts index cd7e91fb81ac4..07efdde6f7b77 100644 --- a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts +++ b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts @@ -10,7 +10,7 @@ import pMap from 'p-map'; import { agentPolicyService } from '../agent_policy'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from '../api_keys'; -import { SO_SEARCH_LIMIT } from '../../constants'; +import { SO_SEARCH_LIMIT, MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; import { appContextService } from '../app_context'; import { scheduleDeployAgentPoliciesTask } from '../agent_policies/deploy_agent_policies_task'; import { scheduleBumpAgentPoliciesTask } from '../agent_policies/bump_agent_policies_task'; @@ -51,7 +51,7 @@ export async function ensureAgentPoliciesFleetServerKeysAndPolicies({ } }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); diff --git a/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts b/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts index db85e269dc345..bb9def3dc4ae6 100644 --- a/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts +++ b/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts @@ -9,7 +9,11 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/ import pMap from 'p-map'; import type { Logger } from '@kbn/logging'; -import { PACKAGES_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT } from '../../constants'; +import { + MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS, + PACKAGES_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, +} from '../../constants'; import { FLEET_INSTALL_FORMAT_VERSION } from '../../constants/fleet_es_assets'; import type { Installation } from '../../types'; @@ -59,6 +63,6 @@ export async function upgradePackageInstallVersion({ } }); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ); } diff --git a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts index e123ca4426654..50f20443c3262 100644 --- a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts @@ -23,9 +23,10 @@ import { ENROLLMENT_API_KEYS_INDEX } from '../../constants'; import { packagePolicyService } from '../package_policy'; import { FleetError, HostedAgentPolicyRestrictionRelatedError } from '../../errors'; -import { isSpaceAwarenessEnabled } from './helpers'; import type { UninstallTokenSOAttributes } from '../security/uninstall_token_service'; +import { isSpaceAwarenessEnabled } from './helpers'; + export async function updateAgentPolicySpaces({ agentPolicyId, currentSpaceId, diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index 4f131d00bdf38..cc7dabe253ec1 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -135,7 +135,7 @@ export const AgentPolicyBaseSchema = { monitoring_pprof_enabled: schema.maybe(schema.boolean()), monitoring_http: schema.maybe( schema.object({ - enabled: schema.boolean(), + enabled: schema.maybe(schema.boolean()), host: schema.maybe(schema.string({ defaultValue: 'localhost' })), port: schema.maybe(schema.number({ min: 0, max: 65353, defaultValue: 6791 })), buffer: schema.maybe(schema.object({ enabled: schema.boolean({ defaultValue: false }) })), diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts index a5fb3e9e034ed..9df9b73b3f49b 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts @@ -138,22 +138,25 @@ export const AgentResponseSchema = schema.object({ upgraded_at: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), upgrade_started_at: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), upgrade_details: schema.maybe( - schema.object({ - target_version: schema.string(), - action_id: schema.string(), - state: AgentUpgradeStateTypeSchema, - metadata: schema.maybe( - schema.object({ - scheduled_at: schema.maybe(schema.string()), - download_percent: schema.maybe(schema.number()), - download_rate: schema.maybe(schema.number()), - failed_state: schema.maybe(AgentUpgradeStateTypeSchema), - error_msg: schema.maybe(schema.string()), - retry_error_msg: schema.maybe(schema.string()), - retry_until: schema.maybe(schema.string()), - }) - ), - }) + schema.oneOf([ + schema.literal(null), + schema.object({ + target_version: schema.string(), + action_id: schema.string(), + state: AgentUpgradeStateTypeSchema, + metadata: schema.maybe( + schema.object({ + scheduled_at: schema.maybe(schema.string()), + download_percent: schema.maybe(schema.number()), + download_rate: schema.maybe(schema.number()), + failed_state: schema.maybe(AgentUpgradeStateTypeSchema), + error_msg: schema.maybe(schema.string()), + retry_error_msg: schema.maybe(schema.string()), + retry_until: schema.maybe(schema.string()), + }) + ), + }), + ]) ), access_api_key_id: schema.maybe(schema.string()), default_api_key: schema.maybe(schema.string()), diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx index f254c7d525759..20ca1fbc82a2f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx @@ -33,7 +33,6 @@ import { useKibana, useFormIsModified, } from '../../../shared_imports'; -import { toasts } from '../../services/notification'; import { getPoliciesListPath, getPolicyViewPath } from '../../services/navigation'; import { UseField } from './form'; import { savePolicy } from './save_policy'; @@ -137,25 +136,21 @@ export const EditPolicy: React.FunctionComponent = () => { const { data: policy, isValid } = await form.submit(); if (!isValid) { - toasts.addDanger( - i18n.translate('xpack.indexLifecycleMgmt.editPolicy.formErrorsMessage', { - defaultMessage: 'Please fix the errors on this page.', - }) - ); - } else { - const name = getPolicyName(); - setHasSubmittedForm(true); - const success = await savePolicy( - { - ...policy, - name, - }, - isNewPolicy || isClonedPolicy - ); - - if (success) { - backToPolicyList(name); - } + return; + } + + const name = getPolicyName(); + setHasSubmittedForm(true); + const success = await savePolicy( + { + ...policy, + name, + }, + isNewPolicy || isClonedPolicy + ); + + if (success) { + backToPolicyList(name); } }; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx index a9675b592aa39..e9d93e6baf631 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx @@ -57,10 +57,6 @@ describe('Create enrich policy', () => { beforeEach(async () => { httpRequestsMockHelpers.setGetMatchingIndices(getMatchingIndices()); - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); httpRequestsMockHelpers.setGetMatchingDataStreams(getMatchingDataStreams()); await act(async () => { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts index 0504f9bf40b7a..a9f1dac15ed1f 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts @@ -188,9 +188,6 @@ const registerHttpRequestMockHelpers = ( error ); - const setGetPrivilegesResponse = (response?: HttpResponse, error?: ResponseError) => - mockResponse('GET', `${INTERNAL_API_BASE_PATH}/enrich_policies/privileges`, response, error); - const setCreateEnrichPolicy = (response?: HttpResponse, error?: ResponseError) => mockResponse('POST', `${INTERNAL_API_BASE_PATH}/enrich_policies`, response, error); @@ -253,7 +250,6 @@ const registerHttpRequestMockHelpers = ( setCreateIndexResponse, setGetMatchingIndices, setGetFieldsFromIndices, - setGetPrivilegesResponse, setCreateEnrichPolicy, setInferenceModels, setGetMatchingDataStreams, diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx index 633ed96ec8225..24f641ae2833f 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx @@ -91,6 +91,11 @@ const appDependencies = { overlays: { openConfirm: jest.fn(), }, + privs: { + monitor: true, + manageEnrich: true, + monitorEnrich: true, + }, } as any; export const kibanaVersion = new SemVer(MAJOR_VERSION); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx index 77c7757fe9202..040602a058e25 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx @@ -38,11 +38,6 @@ describe('Enrich policies tab', () => { describe('empty states', () => { beforeEach(async () => { setDelayResponse(false); - - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); }); test('displays a loading prompt', async () => { @@ -82,24 +77,6 @@ describe('Enrich policies tab', () => { }); }); - describe('permissions check', () => { - it('shows a permissions error when the user does not have sufficient privileges', async () => { - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: false, - missingPrivileges: { cluster: ['manage_enrich'] }, - }); - - testBed = await setup(httpSetup); - await act(async () => { - testBed.actions.goToEnrichPoliciesTab(); - }); - - testBed.component.update(); - - expect(testBed.exists('enrichPoliciesInsuficientPrivileges')).toBe(true); - }); - }); - describe('policies list', () => { let testPolicy: ReturnType; beforeEach(async () => { @@ -110,11 +87,6 @@ describe('Enrich policies tab', () => { createTestEnrichPolicy('policy-range', 'range'), ]); - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); - testBed = await setup(httpSetup); await act(async () => { testBed.actions.goToEnrichPoliciesTab(); diff --git a/x-pack/plugins/index_management/__jest__/components/index_table.test.js b/x-pack/plugins/index_management/__jest__/components/index_table.test.js index 2ae162b421001..0a59fef7be6e6 100644 --- a/x-pack/plugins/index_management/__jest__/components/index_table.test.js +++ b/x-pack/plugins/index_management/__jest__/components/index_table.test.js @@ -168,6 +168,11 @@ describe('index table', () => { enableIndexActions: true, enableIndexStats: true, }, + privs: { + monitor: true, + manageEnrich: true, + monitorEnrich: true, + }, }; component = ( diff --git a/x-pack/plugins/index_management/public/application/app_context.tsx b/x-pack/plugins/index_management/public/application/app_context.tsx index 6df01a109a036..3573ae33812d9 100644 --- a/x-pack/plugins/index_management/public/application/app_context.tsx +++ b/x-pack/plugins/index_management/public/application/app_context.tsx @@ -80,6 +80,11 @@ export interface AppDependencies { kibanaVersion: SemVer; overlays: OverlayStart; canUseSyntheticSource: boolean; + privs: { + monitor: boolean; + manageEnrich: boolean; + monitorEnrich: boolean; + }; } export const AppContextProvider = ({ diff --git a/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx b/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx deleted file mode 100644 index 09a79343b2210..0000000000000 --- a/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { FunctionComponent } from 'react'; - -import { - PageLoading, - PageError, - useAuthorizationContext, - WithPrivileges, - NotAuthorizedSection, -} from '../../../shared_imports'; -import { ENRICH_POLICIES_REQUIRED_PRIVILEGES } from '../../constants'; - -export const EnrichPoliciesWithPrivileges: FunctionComponent<{ - children?: React.ReactNode; -}> = ({ children }) => { - const { apiError } = useAuthorizationContext(); - - if (apiError) { - return ( - - } - error={apiError} - /> - ); - } - - return ( - `cluster.${privilege}`)} - > - {({ isLoading, hasPrivileges, privilegesMissing }) => { - if (isLoading) { - return ( - - - - ); - } - - if (!hasPrivileges) { - return ( - - } - message={ - - } - /> - ); - } - - return <>{children}; - }} - - ); -}; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx index a66811d41b94f..428189acf8559 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx @@ -108,6 +108,7 @@ export const SearchResultItem = React.memo(function FieldListItemFlatComponent({ 'mappingsEditor__fieldsListItem__content--toggle': hasChildFields || hasMultiFields, 'mappingsEditor__fieldsListItem__content--multiField': isMultiField, })} + tabIndex={0} > = () => { +export const EnrichPolicyCreate: React.FunctionComponent = () => { useEffect(() => { breadcrumbService.setBreadcrumbs(IndexManagementBreadcrumb.enrichPoliciesCreate); }, []); @@ -64,11 +60,3 @@ const CreateView: React.FunctionComponent = () => { ); }; - -export const EnrichPolicyCreate: React.FunctionComponent = (props) => ( - - - - - -); diff --git a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx index a036273ebdde9..eeba7b9e03fd8 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx @@ -17,10 +17,6 @@ import { APP_WRAPPER_CLASS, useExecutionContext } from '../../../../shared_impor import { useAppContext } from '../../../app_context'; import { useRedirectPath } from '../../../hooks/redirect_path'; -import { - EnrichPoliciesAuthProvider, - EnrichPoliciesWithPrivileges, -} from '../../../components/enrich_policies'; import { breadcrumbService, IndexManagementBreadcrumb } from '../../../services/breadcrumbs'; import { documentationService } from '../../../services/documentation'; import { useLoadEnrichPolicies } from '../../../services/api'; @@ -34,9 +30,13 @@ const getEnrichPolicyNameFromLocation = (location: Location) => { return policy; }; -const ListView: React.FunctionComponent = ({ history, location }) => { +export const EnrichPoliciesList: React.FunctionComponent = ({ + history, + location, +}) => { const { core: { executionContext }, + privs, } = useAppContext(); const redirectTo = useRedirectPath(history); @@ -79,7 +79,7 @@ const ListView: React.FunctionComponent = ({ history, locat return ; } - if (policies?.length === 0) { + if (privs.manageEnrich && policies?.length === 0) { return ; } @@ -151,11 +151,3 @@ const ListView: React.FunctionComponent = ({ history, locat
        ); }; - -export const EnrichPoliciesList: React.FunctionComponent = (props) => ( - - - - - -); diff --git a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx index e78e08b829997..61574a70fa545 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx @@ -33,43 +33,84 @@ export const PoliciesTable: FunctionComponent = ({ onDeletePolicyClick, onExecutePolicyClick, }) => { - const { history } = useAppContext(); + const { history, privs } = useAppContext(); - const renderToolsRight = () => { - return [ - - - , - - - , - ]; - }; + const createBtn = ( + + + + ); + + const toolsRight = [ + + + , + ]; + + if (privs.manageEnrich) { + toolsRight.push(createBtn); + } const search: EuiSearchBarProps = { - toolsRight: renderToolsRight(), + toolsRight, box: { incremental: true, }, }; + const actions: EuiBasicTableColumn = { + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.actionsField', { + defaultMessage: 'Actions', + }), + actions: [ + { + isPrimary: true, + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeAction', { + defaultMessage: 'Execute', + }), + description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeDescription', { + defaultMessage: 'Execute this enrich policy', + }), + type: 'icon', + icon: 'play', + 'data-test-subj': 'executePolicyButton', + onClick: ({ name }) => onExecutePolicyClick(name), + }, + { + isPrimary: true, + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteAction', { + defaultMessage: 'Delete', + }), + description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteDescription', { + defaultMessage: 'Delete this enrich policy', + }), + type: 'icon', + icon: 'trash', + color: 'danger', + 'data-test-subj': 'deletePolicyButton', + onClick: ({ name }) => onDeletePolicyClick(name), + }, + ], + }; + const columns: Array> = [ { field: 'name', @@ -120,42 +161,12 @@ export const PoliciesTable: FunctionComponent = ({ truncateText: true, render: (fields: string[]) => {fields.join(', ')}, }, - { - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.actionsField', { - defaultMessage: 'Actions', - }), - actions: [ - { - isPrimary: true, - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeAction', { - defaultMessage: 'Execute', - }), - description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeDescription', { - defaultMessage: 'Execute this enrich policy', - }), - type: 'icon', - icon: 'play', - 'data-test-subj': 'executePolicyButton', - onClick: ({ name }) => onExecutePolicyClick(name), - }, - { - isPrimary: true, - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteAction', { - defaultMessage: 'Delete', - }), - description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteDescription', { - defaultMessage: 'Delete this enrich policy', - }), - type: 'icon', - icon: 'trash', - color: 'danger', - 'data-test-subj': 'deletePolicyButton', - onClick: ({ name }) => onDeletePolicyClick(name), - }, - ], - }, ]; + if (privs.manageEnrich) { + columns.push(actions); + } + const { pageSize, sorting, onTableChange } = useEuiTablePersist({ tableId: 'enrichPolicies', initialPageSize: 50, diff --git a/x-pack/plugins/index_management/public/application/sections/home/home.tsx b/x-pack/plugins/index_management/public/application/sections/home/home.tsx index e7de896fa4b38..2d0fc7d4ec108 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/home.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/home.tsx @@ -41,6 +41,7 @@ export const IndexManagementHome: React.FunctionComponent { const { plugins: { console: consolePlugin }, + privs, } = useAppContext(); const tabs = [ { @@ -74,7 +75,10 @@ export const IndexManagementHome: React.FunctionComponent ), }, - { + ]; + + if (privs.monitorEnrich) { + tabs.push({ id: Section.EnrichPolicies, name: ( ), - }, - ]; + }); + } const onSectionChange = (newSection: Section) => { history.push(`/${newSection}`); @@ -143,7 +147,9 @@ export const IndexManagementHome: React.FunctionComponent - + {privs.monitorEnrich && ( + + )} {consolePlugin?.EmbeddableConsole ? : null} diff --git a/x-pack/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts index 82ba6505696aa..06adcc75d80b3 100644 --- a/x-pack/plugins/index_management/public/plugin.ts +++ b/x-pack/plugins/index_management/public/plugin.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { Subject } from 'rxjs'; import SemVer from 'semver/classes/semver'; import { @@ -14,6 +15,7 @@ import { Plugin, PluginInitializerContext, ScopedHistory, + Capabilities, } from '@kbn/core/public'; import { IndexManagementPluginSetup, @@ -61,6 +63,8 @@ export class IndexMgmtUIPlugin private canUseSyntheticSource: boolean = false; private licensingSubscription?: Subscription; + private capabilities$ = new Subject(); + constructor(ctx: PluginInitializerContext) { // Temporary hack to provide the service instances in module files in order to avoid a big refactor // For the selectors we should expose them through app dependencies and read them from there on each container component. @@ -98,29 +102,34 @@ export class IndexMgmtUIPlugin coreSetup: CoreSetup, plugins: SetupDependencies ): IndexManagementPluginSetup { - if (this.config.isIndexManagementUiEnabled) { - const { fleet, usageCollection, management, cloud } = plugins; + const { fleet, usageCollection, management, cloud } = plugins; - management.sections.section.data.registerApp({ - id: PLUGIN.id, - title: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }), - order: 0, - mount: async (params) => { - const { mountManagementSection } = await import('./application/mount_management_section'); - return mountManagementSection({ - coreSetup, - usageCollection, - params, - extensionsService: this.extensionsService, - isFleetEnabled: Boolean(fleet), - kibanaVersion: this.kibanaVersion, - config: this.config, - cloud, - canUseSyntheticSource: this.canUseSyntheticSource, - }); - }, - }); - } + this.capabilities$.subscribe((capabilities) => { + const { monitor, manageEnrich, monitorEnrich } = capabilities.index_management; + if (this.config.isIndexManagementUiEnabled && (monitor || manageEnrich || monitorEnrich)) { + management.sections.section.data.registerApp({ + id: PLUGIN.id, + title: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }), + order: 0, + mount: async (params) => { + const { mountManagementSection } = await import( + './application/mount_management_section' + ); + return mountManagementSection({ + coreSetup, + usageCollection, + params, + extensionsService: this.extensionsService, + isFleetEnabled: Boolean(fleet), + kibanaVersion: this.kibanaVersion, + config: this.config, + cloud, + canUseSyntheticSource: this.canUseSyntheticSource, + }); + }, + }); + } + }); this.locator = plugins.share.url.locators.create( new IndexManagementLocatorDefinition({ @@ -138,6 +147,8 @@ export class IndexMgmtUIPlugin public start(coreStart: CoreStart, plugins: StartDependencies): IndexManagementPluginStart { const { fleet, usageCollection, cloud, share, console, ml, licensing } = plugins; + this.capabilities$.next(coreStart.application.capabilities); + this.licensingSubscription = licensing?.license$.subscribe((next) => { this.canUseSyntheticSource = next.hasAtLeast('enterprise'); }); diff --git a/x-pack/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts index 0ba15c463d4ec..ab6b058cddc78 100644 --- a/x-pack/plugins/index_management/server/plugin.ts +++ b/x-pack/plugins/index_management/server/plugin.ts @@ -37,15 +37,20 @@ export class IndexMgmtServerPlugin implements Plugin { + const { root, errors } = parse(query); + // don't try modifying anything if the query is not syntactically correct + if (errors) { + return { + output: query, + corrections: [], + }; + } + + const corrections = correctAll(root); + + const multiline = /\r?\n/.test(query); + const formattedQuery = BasicPrettyPrinter.print(root, { multiline, pipeTab: '' }); + + return { + output: formattedQuery, + corrections, + }; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts new file mode 100644 index 0000000000000..76ffd993bb9ab --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ESQLAstQueryExpression } from '@kbn/esql-ast'; +import type { QueryCorrection } from './types'; +import { correctTimespanLiterals } from './timespan_literals'; +import { correctLikeWildcards } from './like'; + +export type { QueryCorrection } from './types'; + +export const correctAll = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + corrections.push(...correctTimespanLiterals(query)); + corrections.push(...correctLikeWildcards(query)); + return corrections; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts new file mode 100644 index 0000000000000..81779188c553b --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { parse, BasicPrettyPrinter } from '@kbn/esql-ast'; +import { correctLikeWildcards } from './like'; + +describe('correctLikeWildcards', () => { + it('replaces badly used "_" wildcard', () => { + const query = 'FROM logs | WHERE message LIKE "ba_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "ba?"'); + }); + + it('replaces badly used "%" wildcard', () => { + const query = 'FROM logs | WHERE message LIKE "b%"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "b*"'); + }); + + it('replaces multiple bad wildcards', () => { + const query = 'FROM logs | WHERE message LIKE "a__t%"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "a??t*"'); + }); + + it('replaces bad wildcards in multiple commands and functions', () => { + const query = + 'FROM logs | WHERE message LIKE "a%" AND TO_UPPER(level) LIKE "err%" | WHERE foo LIKE "ba_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual( + 'FROM logs | WHERE message LIKE "a*" AND TO_UPPER(level) LIKE "err*" | WHERE foo LIKE "ba?"' + ); + }); + + it('does not replace escaped characters', () => { + const query = 'FROM logs | WHERE message LIKE "ba\\\\_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "ba\\\\_"'); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts new file mode 100644 index 0000000000000..be61bd216284b --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Walker, type ESQLAstQueryExpression } from '@kbn/esql-ast'; +import { isLikeOperatorNode, isStringLiteralNode } from '../typeguards'; +import type { ESQLLikeOperator, ESQLStringLiteral } from '../types'; +import type { QueryCorrection } from './types'; + +/** + * Correct wrong LIKE wildcard mistakes. + * The LLM can make mistake and use SQL wildcards for LIKE operators. + * + * E.g. + * `column LIKE "ba_"` => `column LIKE "ba?"` + * `column LIKE "ba%"` => `column LIKE "ba*"` + */ +export const correctLikeWildcards = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + + Walker.walk(query, { + visitFunction: (node) => { + if (isLikeOperatorNode(node)) { + corrections.push(...checkLikeNode(node)); + } + }, + }); + + return corrections; +}; + +function checkLikeNode(node: ESQLLikeOperator): QueryCorrection[] { + if (node.args.length !== 2 || !isStringLiteralNode(node.args[1])) { + return []; + } + const likeExpression = node.args[1] as ESQLStringLiteral; + + const initialValue = likeExpression.value; + + likeExpression.value = likeExpression.value + .replaceAll(/(? { + describe('with DATE_TRUNC', () => { + it('replaces a timespan with a proper timespan literal', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 year", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 year, date)"` + ); + }); + + it('replaces a timespan without quantity', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("month", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 month, date)"` + ); + }); + + it('replaces uppercase literals', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 YEAR", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 year, date)"` + ); + }); + + it('returns info about the correction', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 year", date)'; + const { root } = parse(query); + + const corrections = correctTimespanLiterals(root); + + expect(corrections).toHaveLength(1); + expect(corrections[0]).toEqual({ + type: 'string_as_timespan_literal', + description: + 'Replaced string literal with timespan literal in DATE_TRUNC function at position 29', + node: expect.any(Object), + }); + }); + }); + + describe('with BUCKET', () => { + it('replaces a timespan with a proper timespan literal', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, "1 week")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, 1 week)"` + ); + }); + + it('replaces a timespan without quantity', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "hour")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, 1 hour)"` + ); + }); + + it('replaces uppercase literals', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, "1 WEEK")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, 1 week)"` + ); + }); + + it('returns info about the correction', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "hour")'; + const { root } = parse(query); + + const corrections = correctTimespanLiterals(root); + + expect(corrections).toHaveLength(1); + expect(corrections[0]).toEqual({ + type: 'string_as_timespan_literal', + description: + 'Replaced string literal with timespan literal in BUCKET function at position 45', + node: expect.any(Object), + }); + }); + }); + + describe('with mixed usages', () => { + it('find all occurrences in a complex query', () => { + const query = `FROM logs + | EVAL trunc_year = DATE_TRUNC("1 year", date) + | EVAL trunc_month = DATE_TRUNC("month", date) + | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "3 hour")`; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root, { multiline: true, pipeTab: '' }); + + expect(output).toMatchInlineSnapshot(` + "FROM logs + | EVAL trunc_year = DATE_TRUNC(1 year, date) + | EVAL trunc_month = DATE_TRUNC(1 month, date) + | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, 3 hour)" + `); + }); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.ts new file mode 100644 index 0000000000000..039632c3d103f --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.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 { Walker, type ESQLAstQueryExpression } from '@kbn/esql-ast'; +import { isDateTruncFunctionNode, isBucketFunctionNode, isStringLiteralNode } from '../typeguards'; +import type { ESQLDateTruncFunction, ESQLBucketFunction } from '../types'; +import { stringToTimespanLiteral, isTimespanString } from '../ast_tools/timespan'; +import { QueryCorrection } from './types'; + +/** + * Correct timespan literal grammar mistakes, and returns the list of corrections that got applied. + * + * E.g. + * `DATE_TRUNC("YEAR", @timestamp)` => `DATE_TRUNC(1 year, @timestamp)` + * `BUCKET(@timestamp, "1 week")` => `BUCKET(@timestamp, 1 week)` + * + */ +export const correctTimespanLiterals = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + + Walker.walk(query, { + visitFunction: (node) => { + if (isDateTruncFunctionNode(node)) { + corrections.push(...checkDateTrunc(node)); + } + if (isBucketFunctionNode(node)) { + corrections.push(...checkBucket(node)); + } + }, + }); + + return corrections; +}; + +function checkDateTrunc(node: ESQLDateTruncFunction): QueryCorrection[] { + if (node.args.length !== 2) { + return []; + } + + const firstArg = node.args[0]; + + if (isStringLiteralNode(firstArg) && isTimespanString(firstArg.value)) { + const replacement = stringToTimespanLiteral(firstArg.value); + node.args[0] = replacement; + + const correction: QueryCorrection = { + type: 'string_as_timespan_literal', + node, + description: `Replaced string literal with timespan literal in DATE_TRUNC function at position ${node.location.min}`, + }; + return [correction]; + } + + return []; +} + +function checkBucket(node: ESQLBucketFunction): QueryCorrection[] { + // only checking the 2 args version - e.g. BUCKET(hire_date, 1 week) + if (node.args.length !== 2) { + return []; + } + + const secondArg = node.args[1]; + + if (isStringLiteralNode(secondArg) && isTimespanString(secondArg.value)) { + const replacement = stringToTimespanLiteral(secondArg.value); + node.args[1] = replacement; + + const correction: QueryCorrection = { + type: 'string_as_timespan_literal', + node, + description: `Replaced string literal with timespan literal in BUCKET function at position ${node.location.min}`, + }; + return [correction]; + } + + return []; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts new file mode 100644 index 0000000000000..dc1210c84acc2 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ESQLSingleAstItem } from '@kbn/esql-ast'; + +/** + * Represents a correction that was applied to the query + */ +export interface QueryCorrection { + /** The type of correction */ + type: string; + /** A human-friendly-ish description of the correction */ + description: string; + /** The parent node the correction was applied to */ + node: ESQLSingleAstItem; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/index.ts new file mode 100644 index 0000000000000..d0e1a4808829a --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/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 { correctQueryWithAst } from './correct_with_ast'; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.ts new file mode 100644 index 0000000000000..54bbe2f7300a9 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.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 type { + ESQLSingleAstItem, + ESQLAstItem, + ESQLFunction, + ESQLLiteral, + ESQLColumn, +} from '@kbn/esql-ast'; +import type { + ESQLStringLiteral, + ESQLDateTruncFunction, + ESQLBucketFunction, + ESQLLikeOperator, +} from './types'; + +export function isSingleItem(item: ESQLAstItem): item is ESQLSingleAstItem { + return Object.hasOwn(item, 'type'); +} + +export function isFunctionNode(node: ESQLAstItem): node is ESQLFunction { + return isSingleItem(node) && node.type === 'function'; +} + +export function isColumnNode(node: ESQLAstItem): node is ESQLColumn { + return isSingleItem(node) && node.type === 'column'; +} + +export function isLiteralNode(node: ESQLAstItem): node is ESQLLiteral { + return isSingleItem(node) && node.type === 'literal'; +} + +export function isStringLiteralNode(node: ESQLAstItem): node is ESQLStringLiteral { + return isLiteralNode(node) && node.literalType === 'keyword'; +} + +export function isDateTruncFunctionNode(node: ESQLAstItem): node is ESQLDateTruncFunction { + return isFunctionNode(node) && node.subtype === 'variadic-call' && node.name === 'date_trunc'; +} + +export function isBucketFunctionNode(node: ESQLAstItem): node is ESQLBucketFunction { + return isFunctionNode(node) && node.subtype === 'variadic-call' && node.name === 'bucket'; +} + +export function isLikeOperatorNode(node: ESQLAstItem): node is ESQLLikeOperator { + return isFunctionNode(node) && node.subtype === 'binary-expression' && node.name === 'like'; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.ts new file mode 100644 index 0000000000000..6444f1490f3d2 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.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 { ESQLFunction, ESQLLiteral } from '@kbn/esql-ast'; + +/** + * represents a DATE_TRUNC function node. + */ +export type ESQLDateTruncFunction = ESQLFunction<'variadic-call', 'date_trunc'>; + +/** + * represents a LIKE function node. + */ +export type ESQLLikeOperator = ESQLFunction<'binary-expression', 'like'>; + +/** + * represents a BUCKET function node. + */ +export type ESQLBucketFunction = ESQLFunction<'variadic-call', 'bucket'>; + +/** + * represents an ESQL string literal. + */ +export type ESQLStringLiteral = Extract; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts new file mode 100644 index 0000000000000..22ae55f772e95 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { correctCommonEsqlMistakes } from './correct_esql_query'; + +jest.mock('./ast'); +jest.mock('./non_ast'); +import { correctQueryWithAst } from './ast'; +import { correctCommonEsqlMistakes as correctQueryWithoutAst } from './non_ast'; + +const correctQueryWithAstMock = correctQueryWithAst as jest.MockedFn; +const correctQueryWithoutAstMock = correctQueryWithoutAst as jest.MockedFn< + typeof correctQueryWithoutAst +>; + +describe('correctCommonEsqlMistakes', () => { + beforeEach(() => { + correctQueryWithoutAstMock.mockImplementation((query) => { + return { + input: query, + output: query, + isCorrection: false, + }; + }); + correctQueryWithAstMock.mockImplementation((query) => { + return { + output: query, + corrections: [], + }; + }); + }); + + afterEach(() => { + correctQueryWithoutAstMock.mockReset(); + correctQueryWithAstMock.mockReset(); + }); + + it('calls correctQueryWithoutAst with the right parameters', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + correctCommonEsqlMistakes(inputQuery); + + expect(correctQueryWithoutAstMock).toHaveBeenCalledTimes(1); + expect(correctQueryWithoutAstMock).toHaveBeenCalledWith(inputQuery); + }); + + it('calls correctQueryWithAst with the right parameters', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + const correctQueryWithoutAstResult = 'FROM logs | WHERE foo > dolly'; + + correctQueryWithoutAstMock.mockImplementation((query) => { + return { + input: inputQuery, + output: correctQueryWithoutAstResult, + isCorrection: true, + }; + }); + + correctCommonEsqlMistakes(inputQuery); + + expect(correctQueryWithAstMock).toHaveBeenCalledTimes(1); + expect(correctQueryWithAstMock).toHaveBeenCalledWith(correctQueryWithoutAstResult); + }); + + it('returns the corrected query', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + const correctQueryWithAstResult = 'FROM logs | WHERE foo > dolly'; + + correctQueryWithAstMock.mockImplementation((query) => { + return { + output: correctQueryWithAstResult, + corrections: [], + }; + }); + + const { input, output } = correctCommonEsqlMistakes(inputQuery); + + expect(input).toEqual(inputQuery); + expect(output).toEqual(correctQueryWithAstResult); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts new file mode 100644 index 0000000000000..4ad96323cc7ea --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { correctQueryWithAst } from './ast'; +import { correctCommonEsqlMistakes as correctQueryWithoutAst } from './non_ast'; + +/** + * Correct some common ES|QL syntax and grammar mistakes that LLM can potentially do. + * + * Correcting the query is done in two steps: + * 1. we try to correct the *syntax*, without AST (given it requires a valid syntax) + * 2. we try to correct the *grammar*, using AST this time. + */ +export const correctCommonEsqlMistakes = (query: string) => { + const { output: outputWithoutAst, isCorrection: correctionWithoutAst } = + correctQueryWithoutAst(query); + const { output: corrected, corrections } = correctQueryWithAst(outputWithoutAst); + return { + input: query, + output: corrected, + isCorrection: correctionWithoutAst || corrections.length > 0, + }; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts deleted file mode 100644 index 818f4854e038d..0000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { correctQueryWithActions } from './correct_query_with_actions'; - -describe('correctQueryWithActions', () => { - it(`fixes errors correctly for a query with one syntax error for stats`, async () => { - const fixedQuery = await correctQueryWithActions('from logstash-* | stats aveg(bytes)'); - expect(fixedQuery).toBe('from logstash-* | stats avg(bytes)'); - }); - - it(`fixes errors correctly for a query with 2 syntax errors for stats`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats aveg(bytes), max2(bytes)' - ); - expect(fixedQuery).toBe('from logstash-* | stats avg(bytes), max(bytes)'); - }); - - it(`fixes errors correctly for a query with one syntax error for eval`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats var0 = max(bytes) | eval ab(var0) | limit 1' - ); - expect(fixedQuery).toBe('from logstash-* | stats var0 = max(bytes) | eval abs(var0) | limit 1'); - }); - - it(`fixes errors correctly for a query with two syntax error for eval`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats var0 = max2(bytes) | eval ab(var0) | limit 1' - ); - expect(fixedQuery).toBe('from logstash-* | stats var0 = max(bytes) | eval abs(var0) | limit 1'); - }); - - it(`doesnt complain for @timestamp column`, async () => { - const queryWithTimestamp = `FROM logstash-* - | WHERE @timestamp >= NOW() - 15 minutes - | EVAL bucket = DATE_TRUNC(1 minute, @timestamp) - | STATS avg_cpu = AVG(system.cpu.total.norm.pct) BY service.name, bucket - | SORT avg_cpu DESC - | LIMIT 10`; - const fixedQuery = await correctQueryWithActions(queryWithTimestamp); - expect(fixedQuery).toBe(queryWithTimestamp); - }); -}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts deleted file mode 100644 index 30e2c11adb6de..0000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts +++ /dev/null @@ -1,63 +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 { validateQuery, getActions } from '@kbn/esql-validation-autocomplete'; -import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; - -const fixedQueryByOneAction = async (queryString: string) => { - const { errors } = await validateQuery(queryString, getAstAndSyntaxErrors, { - ignoreOnMissingCallbacks: true, - }); - - const actions = await getActions(queryString, errors, getAstAndSyntaxErrors, { - relaxOnMissingCallbacks: true, - }); - - if (actions.length) { - const [firstAction] = actions; - const range = firstAction.edits[0].range; - const correctText = firstAction.edits[0].text; - const problematicString = queryString.substring(range.startColumn - 1, range.endColumn - 1); - const fixedQuery = queryString.replace(problematicString, correctText); - - return { - query: fixedQuery, - shouldRunAgain: Boolean(actions.length), - }; - } - return { - query: queryString, - shouldRunAgain: false, - }; -}; - -/** - * @param queryString - * @returns corrected queryString - * The cases that are handled are: - * - Query stats / eval functions have typos e.g. aveg instead of avg - * - Unquoted fields e.g. keep field-1 instead of keep `field-1` - * - Unquoted fields in stats or eval e.g. stats avg(field-1) instead of stats avg(`field-1`) - * - Combination of the above - */ - -export const correctQueryWithActions = async (queryString: string) => { - let shouldCorrectQuery = true; - let fixedQuery = queryString; - // this is an escape hatch, the loop will end automatically if the ast doesnt return more actions - // in case it goes wrong, we allow it to loop 10 times - let limit = 10; - - while (shouldCorrectQuery && limit >= 0) { - const { query, shouldRunAgain } = await fixedQueryByOneAction(fixedQuery); - shouldCorrectQuery = shouldRunAgain; - fixedQuery = query; - limit--; - } - - return fixedQuery; -}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.ts deleted file mode 100644 index 04d99aede62b8..0000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.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 { getErrorsWithCommands } from './get_errors_with_commands'; - -describe('getErrorsWithCommands', () => { - it('returns the command associated with the error', () => { - expect( - getErrorsWithCommands(`FROM logs-* | WHERE @timestamp <= NOW() | STATS BY host.name`, [ - { - type: 'error', - text: 'Syntax error', - code: '', - location: { - min: 24, - max: 36, - }, - }, - ]) - ).toEqual(['Error in `| WHERE @timestamp <= NOW()`:\n Syntax error']); - }); -}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts deleted file mode 100644 index b25c79161f79b..0000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { EditorError, ESQLMessage } from '@kbn/esql-ast'; -import { splitIntoCommands } from './correct_common_esql_mistakes'; - -export function getErrorsWithCommands(query: string, errors: Array) { - const asCommands = splitIntoCommands(query); - - const errorMessages = errors.map((error) => { - if ('location' in error) { - const commandsUntilEndOfError = splitIntoCommands(query.substring(0, error.location.max)); - const lastCompleteCommand = asCommands[commandsUntilEndOfError.length - 1]; - if (lastCompleteCommand) { - return `Error in \`| ${lastCompleteCommand.command}\`:\n ${error.text}`; - } - } - return 'text' in error ? error.text : error.message; - }); - - return errorMessages; -} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts new file mode 100644 index 0000000000000..2efacc374e8cd --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { correctCommonEsqlMistakes } from './correct_esql_query'; +export { splitIntoCommands } from './non_ast'; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts similarity index 99% rename from x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts rename to x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts index 8c6b90bca76ab..9d4b064b35f61 100644 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { correctCommonEsqlMistakes } from './correct_common_esql_mistakes'; describe('correctCommonEsqlMistakes', () => { diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts similarity index 100% rename from x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts rename to x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/index.ts new file mode 100644 index 0000000000000..2752f82ce9c43 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/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 { correctCommonEsqlMistakes, splitIntoCommands } from './correct_common_esql_mistakes'; diff --git a/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts b/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts index 862986ce1c73a..d7520a86d6922 100644 --- a/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts +++ b/x-pack/plugins/inference/public/util/create_observable_from_http_response.ts @@ -26,10 +26,10 @@ export function createObservableFromHttpResponse( } return new Observable((subscriber) => { - const parser = createParser((event) => { - if (event.type === 'event') { + const parser = createParser({ + onEvent: (event) => { subscriber.next(event.data); - } + }, }); const readStream = async () => { diff --git a/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts b/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts index a35491a476040..fba1d75956bf0 100644 --- a/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts +++ b/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts @@ -13,7 +13,7 @@ import Path from 'path'; import yargs, { Argv } from 'yargs'; import { REPO_ROOT } from '@kbn/repo-info'; import { INLINE_ESQL_QUERY_REGEX } from '../../common/tasks/nl_to_esql/constants'; -import { correctCommonEsqlMistakes } from '../../common/tasks/nl_to_esql/correct_common_esql_mistakes'; +import { correctCommonEsqlMistakes } from '../../common/tasks/nl_to_esql'; import { connectorIdOption, elasticsearchOption, kibanaOption } from '../util/cli_options'; import { getServiceUrls } from '../util/get_service_urls'; import { KibanaClient } from '../util/kibana_client'; diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts index 823344f52a891..049e627303d1b 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts @@ -11,7 +11,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import { ESQLSearchResponse, ESQLRow } from '@kbn/es-types'; import { esFieldTypeToKibanaFieldType } from '@kbn/field-types'; import { DatatableColumn, DatatableColumnType } from '@kbn/expressions-plugin/common'; -import { splitIntoCommands } from '../../../common/tasks/nl_to_esql/correct_common_esql_mistakes'; +import { splitIntoCommands } from '../../../common'; export async function runAndValidateEsqlQuery({ query, diff --git a/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts index cad0a8e84d6a7..42844632aa03b 100644 --- a/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts +++ b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts @@ -11,10 +11,10 @@ import { Observable } from 'rxjs'; export function eventSourceStreamIntoObservable(readable: Readable) { return new Observable((subscriber) => { - const parser = createParser((event) => { - if (event.type === 'event') { + const parser = createParser({ + onEvent: (event) => { subscriber.next(event.data); - } + }, }); async function processStream() { diff --git a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts index 8ece214c27599..a815b22854118 100644 --- a/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts +++ b/x-pack/plugins/inference/server/util/observable_into_event_source_stream.test.ts @@ -72,10 +72,10 @@ describe('observableIntoEventSourceStream', () => { const events: Array> = []; - const parser = createParser((event) => { - if (event.type === 'event') { + const parser = createParser({ + onEvent: (event) => { events.push(JSON.parse(event.data)); - } + }, }); chunks.forEach((chunk) => { diff --git a/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts b/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts new file mode 100644 index 0000000000000..b18414610664c --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { GenerationErrorCode } from '../constants'; +import { isGenerationErrorBody } from './generation_error'; +import type { GenerationErrorBody } from './generation_error'; + +describe('isGenerationErrorBody', () => { + it('should return true for a valid GenerationErrorBody object', () => { + const validErrorBody: GenerationErrorBody = { + message: 'An error occurred', + attributes: { + errorCode: GenerationErrorCode.CEF_ERROR, + underlyingMessages: ['Error message 1', 'Error message 2'], + }, + }; + + expect(isGenerationErrorBody(validErrorBody)).toBe(true); + }); + + it('should return false for an object without a message', () => { + const invalidErrorBody = { + attributes: { + errorCode: 'ERROR_CODE', + underlyingMessages: ['Error message 1', 'Error message 2'], + }, + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for an object without attributes', () => { + const invalidErrorBody = { + message: 'An error occurred', + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for an object with invalid attributes', () => { + const invalidErrorBody = { + message: 'An error occurred', + attributes: { + errorCode: 123, // errorCode should be a string + underlyingMessages: 'Error message', // underlyingMessages should be an array + }, + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for a non-object value', () => { + expect(isGenerationErrorBody(null)).toBe(false); + expect(isGenerationErrorBody(undefined)).toBe(false); + expect(isGenerationErrorBody('string')).toBe(false); + expect(isGenerationErrorBody(123)).toBe(false); + expect(isGenerationErrorBody(true)).toBe(false); + }); +}); diff --git a/x-pack/plugins/integration_assistant/common/api/generation_error.ts b/x-pack/plugins/integration_assistant/common/api/generation_error.ts index e96ad8bff9b59..03f01e96bee53 100644 --- a/x-pack/plugins/integration_assistant/common/api/generation_error.ts +++ b/x-pack/plugins/integration_assistant/common/api/generation_error.ts @@ -13,6 +13,12 @@ export interface GenerationErrorBody { attributes: GenerationErrorAttributes; } +export interface ErrorMessageWithLink { + link: string; + linkText: string; + errorMessage: string; +} + export function isGenerationErrorBody(obj: unknown | undefined): obj is GenerationErrorBody { return ( typeof obj === 'object' && @@ -27,7 +33,8 @@ export function isGenerationErrorBody(obj: unknown | undefined): obj is Generati export interface GenerationErrorAttributes { errorCode: GenerationErrorCode; - underlyingMessages: string[] | undefined; + underlyingMessages?: string[] | undefined; + errorMessageWithLink?: ErrorMessageWithLink | undefined; } export function isGenerationErrorAttributes(obj: unknown): obj is GenerationErrorAttributes { diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts index 803f9b8a6c3af..3b8dac7af22ca 100644 --- a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts @@ -84,6 +84,7 @@ export const SamplesFormatName = z.enum([ 'structured', 'unstructured', 'unsupported', + 'cef', ]); export type SamplesFormatNameEnum = typeof SamplesFormatName.enum; export const SamplesFormatNameEnum = SamplesFormatName.enum; diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml index 900b6e362a754..23ad137d8d83a 100644 --- a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml @@ -64,6 +64,7 @@ components: - structured - unstructured - unsupported + - cef SamplesFormat: type: object diff --git a/x-pack/plugins/integration_assistant/common/constants.ts b/x-pack/plugins/integration_assistant/common/constants.ts index 4d791341e34f9..3026101ebf54d 100644 --- a/x-pack/plugins/integration_assistant/common/constants.ts +++ b/x-pack/plugins/integration_assistant/common/constants.ts @@ -35,6 +35,7 @@ export enum GenerationErrorCode { RECURSION_LIMIT_ANALYZE_LOGS = 'recursion-limit-analyze-logs', UNSUPPORTED_LOG_SAMPLES_FORMAT = 'unsupported-log-samples-format', UNPARSEABLE_CSV_DATA = 'unparseable-csv-data', + CEF_ERROR = 'cef-not-supported', } // Size limits diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx new file mode 100644 index 0000000000000..105bacf45e92c --- /dev/null +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx @@ -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 React from 'react'; +import { render } from '@testing-library/react'; +import { ErrorMessage, isErrorMessageWithLink, MessageLink } from './error_with_link'; + +describe('isErrorMessageWithLink', () => { + it('should return true when error is an ErrorMessageWithLink', () => { + const error = { + link: 'http://example.com', + errorMessage: 'An error occurred', + linkText: 'decode_cef', + }; + expect(isErrorMessageWithLink(error)).toBe(true); + }); + + it('should return false when error is a string', () => { + const error = 'An error occurred'; + expect(isErrorMessageWithLink(error)).toBe(false); + }); + + describe('MessageLink', () => { + it('should render link with correct href and text', () => { + const { getByText } = render(); + const linkElement = getByText('decode_cef'); + expect(linkElement).toBeInTheDocument(); + expect(linkElement).toHaveAttribute('href', 'http://example.com'); + }); + }); + + describe('ErrorMessage', () => { + it('should render error message when error is a string', () => { + const error = 'An error occurred'; + const { getByText } = render(); + expect(getByText('An error occurred')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx new file mode 100644 index 0000000000000..8791e9f03a0f8 --- /dev/null +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiLink } from '@elastic/eui'; +import type { ErrorMessageWithLink } from '../../../../../../common/api/generation_error'; + +interface ErrorMessageProps { + error: string | null | ErrorMessageWithLink; +} + +interface MessageLinkProps { + link: string; + linkText: string; +} + +export const isErrorMessageWithLink = ( + error: string | ErrorMessageWithLink | null +): error is ErrorMessageWithLink => { + return ( + (error as ErrorMessageWithLink).link !== undefined && + (error as ErrorMessageWithLink).linkText !== undefined && + (error as ErrorMessageWithLink).errorMessage !== undefined + ); +}; + +export const MessageLink = React.memo(({ link, linkText }) => { + return ( + + {linkText} + + ); +}); +MessageLink.displayName = 'MessageLink'; + +export const ErrorMessage = React.memo(({ error }) => { + return ( + <> + {isErrorMessageWithLink(error) ? ( + , + }} + /> + ) : typeof error === 'string' ? ( + <>{error} + ) : null} + + ); +}); +ErrorMessage.displayName = 'ErrorMessage'; diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx index ba57d83618c13..9d8d52a5b8783 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx @@ -28,6 +28,7 @@ import * as i18n from './translations'; import type { OnComplete, ProgressItem } from './use_generation'; import { ProgressOrder, useGeneration } from './use_generation'; +import { ErrorMessage } from './error_with_link'; const progressText: Record = { analyzeLogs: i18n.PROGRESS_ANALYZE_LOGS, @@ -87,7 +88,7 @@ export const GenerationModal = React.memo( iconType="alert" data-test-subj="generationErrorCallout" > - {error} + ) : ( diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts index ec90568da0ef9..8f2aab49622f0 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts @@ -188,6 +188,13 @@ export const RETRY = i18n.translate('xpack.integrationAssistant.step.dataStream. defaultMessage: 'Retry', }); +export const DECODE_CEF_LINK = i18n.translate( + 'xpack.integrationAssistant.errors.cefFormat.decodeLink', + { + defaultMessage: 'CEF format not supported yet. Instead please use CEF Integration:', + } +); + export const GENERATION_ERROR_TRANSLATION: Record< GenerationErrorCode, string | ((attributes: GenerationErrorAttributes) => string) @@ -211,6 +218,11 @@ export const GENERATION_ERROR_TRANSLATION: Record< defaultMessage: 'Unsupported log format in the samples.', } ), + [GenerationErrorCode.CEF_ERROR]: i18n.translate('xpack.integrationAssistant.errors.cefError', { + // This is a default error message if the linking does not work. + defaultMessage: + 'CEF format detected. Please decode the CEF logs into JSON format using filebeat decode_cef processor.', + }), [GenerationErrorCode.UNPARSEABLE_CSV_DATA]: (attributes) => { if ( attributes.underlyingMessages !== undefined && diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx index 566451d624c5e..de6b2eed038ec 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx @@ -28,6 +28,8 @@ import type { State } from '../../state'; import * as i18n from './translations'; import { useTelemetry } from '../../../telemetry'; import type { AIConnector, IntegrationSettings } from '../../types'; +import type { ErrorMessageWithLink } from '../../../../../../common/api/generation_error'; +import { GenerationErrorCode } from '../../../../../../common/constants'; export type OnComplete = (result: State['result']) => void; export const ProgressOrder = ['analyzeLogs', 'ecs', 'categorization', 'related'] as const; @@ -48,12 +50,23 @@ interface RunGenerationProps { // If the result is classified as a generation error, produce an error message // as defined in the i18n file. Otherwise, return undefined. -function generationErrorMessage(body: unknown | undefined): string | undefined { +function generationErrorMessage( + body: unknown | undefined +): string | ErrorMessageWithLink | undefined { if (!isGenerationErrorBody(body)) { return; } const errorCode = body.attributes.errorCode; + if (errorCode === GenerationErrorCode.CEF_ERROR) { + if (body.attributes.errorMessageWithLink !== undefined) { + return { + link: body.attributes.errorMessageWithLink.link, + errorMessage: i18n.DECODE_CEF_LINK, + linkText: body.attributes.errorMessageWithLink.linkText, + }; + } + } const translation = i18n.GENERATION_ERROR_TRANSLATION[errorCode]; return typeof translation === 'function' ? translation(body.attributes) : translation; } @@ -72,7 +85,7 @@ export const useGeneration = ({ const { reportGenerationComplete } = useTelemetry(); const { http, notifications } = useKibana().services; const [progress, setProgress] = useState(); - const [error, setError] = useState(null); + const [error, setError] = useState(null); const [isRequesting, setIsRequesting] = useState(true); useEffect(() => { diff --git a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts index b6e777a87888a..09a7249a3786c 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts @@ -23,6 +23,7 @@ Follow these steps to do this: b. If there is no csv header then set "header: false" and try to find good names for the columns in the "columns" array by looking into the values of data in those columns. For each column, if you are unable to find good name candidate for it then output an empty string, like in the example. * 'structured': If the log samples have structured message body with key-value pairs then classify it as "name: structured". Look for a flat list of key-value pairs, often separated by some delimiters. Consider variations in formatting, such as quotes around values ("key=value", key="value"), special characters in keys or values, or escape sequences. * 'unstructured': If the log samples have unstructured body like a free-form text then classify it as "name: unstructured". + * 'cef': If the log samples have Common Event Format (CEF) then classify it as "name: cef". * 'unsupported': If you cannot put the format into any of the above categories then classify it with "name: unsupported". 2. Header: for structured and unstructured format: - if the samples have any or all of priority, timestamp, loglevel, hostname, ipAddress, messageId in the beginning information then set "header: true". diff --git a/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.ts b/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.ts new file mode 100644 index 0000000000000..16889b30c1a11 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.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 { KibanaResponseFactory } from '@kbn/core/server'; +import { + GenerationErrorAttributes, + GenerationErrorBody, +} from '../../../common/api/generation_error'; +import { ErrorThatHandlesItsOwnResponse } from './types'; +import { GenerationErrorCode } from '../../../common/constants'; + +export class CefError extends Error implements ErrorThatHandlesItsOwnResponse { + private readonly errorCode: GenerationErrorCode = GenerationErrorCode.CEF_ERROR; + attributes: GenerationErrorAttributes; + + constructor(message: string) { + super(message); + this.attributes = { + errorCode: this.errorCode, + errorMessageWithLink: { + linkText: 'cef-integration', + link: 'https://www.elastic.co/docs/current/integrations/cef', + errorMessage: '', // Will be set using translation in the UI. + }, + }; + } + + public sendResponse(res: KibanaResponseFactory) { + const body: GenerationErrorBody = { + message: this.errorCode, + attributes: this.attributes, + }; + return res.customError({ + statusCode: 501, + body, + }); + } +} diff --git a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts index 34f05fcc82025..37926dac19156 100644 --- a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts @@ -19,6 +19,7 @@ import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse, UnsupportedLogFormatError } from '../lib/errors'; import { handleCustomErrors } from './routes_util'; import { GenerationErrorCode } from '../../common/constants'; +import { CefError } from '../lib/errors/cef_error'; export function registerAnalyzeLogsRoutes( router: IRouter @@ -102,9 +103,16 @@ export function registerAnalyzeLogsRoutes( .withConfig({ runName: 'Log Format' }) .invoke(logFormatParameters, options); const graphLogFormat = graphResults.results.samplesFormat.name; - if (graphLogFormat === 'unsupported') { - throw new UnsupportedLogFormatError(GenerationErrorCode.UNSUPPORTED_LOG_SAMPLES_FORMAT); + + switch (graphLogFormat) { + case 'unsupported': + throw new UnsupportedLogFormatError( + GenerationErrorCode.UNSUPPORTED_LOG_SAMPLES_FORMAT + ); + case 'cef': + throw new CefError(GenerationErrorCode.CEF_ERROR); } + return res.ok({ body: AnalyzeLogsResponse.parse(graphResults) }); } catch (err) { try { diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 73fb52bbe6683..c146352ede566 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -34,7 +34,7 @@ import { setState, LensAppState } from '../state_management'; import { coreMock } from '@kbn/core/public/mocks'; import { LensSerializedState } from '..'; import { createMockedField, createMockedIndexPattern } from '../datasources/form_based/mocks'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { VisualizeEditorContext } from '../types'; @@ -48,7 +48,7 @@ jest.mock('lodash', () => ({ debounce: (fn: unknown) => fn, })); -const defaultSavedObjectId: string = faker.random.uuid(); +const defaultSavedObjectId: string = faker.string.uuid(); const waitToLoad = async () => await act(async () => new Promise((resolve) => setTimeout(resolve, 0))); @@ -233,7 +233,7 @@ describe('Lens App', () => { }); describe('breadcrumbs', () => { - const breadcrumbDocSavedObjectId = faker.random.uuid(); + const breadcrumbDocSavedObjectId = faker.string.uuid(); const breadcrumbDoc = getLensDocumentMock({ savedObjectId: breadcrumbDocSavedObjectId, title: 'Daaaaaaadaumching!', @@ -601,7 +601,7 @@ describe('Lens App', () => { expect(lensStore.getState().lens.applyChangesCounter).toBe(1); }); it('adds to the recently accessed list on save', async () => { - const savedObjectId = faker.random.uuid(); + const savedObjectId = faker.string.uuid(); await save({ savedObjectId, prevSavedObjectId: 'prevId', comesFromDashboard: false }); expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( `/app/lens#/edit/${savedObjectId}`, diff --git a/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts b/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts index 7dc4e8cfda78c..773276710f48d 100644 --- a/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts +++ b/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts @@ -6,7 +6,7 @@ */ import { renderHook, act } from '@testing-library/react-hooks'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { UseNavigateBackToAppProps, useNavigateBackToApp } from './app_helpers'; import { defaultDoc, makeDefaultServices } from '../mocks/services_mock'; import { cloneDeep } from 'lodash'; diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx index 987b320b3abf1..5d9c833174ed5 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx @@ -8,7 +8,7 @@ import { SaveProps } from './app'; import { type SaveVisualizationProps, runSaveLensVisualization } from './save_modal_container'; import { defaultDoc, makeDefaultServices } from '../mocks'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { makeAttributeService } from '../mocks/services_mock'; jest.mock('../persistence/saved_objects_utils/check_for_duplicate_title', () => ({ @@ -241,7 +241,7 @@ describe('runSaveLensVisualization', () => { }); // save the current document as a new by-value copy and add it to a dashboard it('should save as a new by-value copy and redirect to the dashboard', async () => { - const dashboardId = faker.random.uuid(); + const dashboardId = faker.string.uuid(); const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = getDefaultArgs( { @@ -271,7 +271,7 @@ describe('runSaveLensVisualization', () => { // save the current document as a new by-ref copy and add it to a dashboard it('should save as a new by-ref copy and redirect to the dashboard', async () => { - const dashboardId = faker.random.uuid(); + const dashboardId = faker.string.uuid(); const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = getDefaultArgs( { @@ -376,7 +376,7 @@ describe('runSaveLensVisualization', () => { // simulate a new save const attributeServiceMock = makeAttributeService({ ...defaultDoc, - savedObjectId: faker.random.uuid(), + savedObjectId: faker.string.uuid(), }); const { props, saveProps, options, saveToLibraryFn, cleanupEditor } = getDefaultArgs( diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.test.tsx index a140ca22db2b5..b8d3af522c455 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.test.tsx @@ -12,7 +12,7 @@ import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { createMockedIndexPattern } from '../../mocks'; @@ -402,7 +402,7 @@ describe('percentile', () => { it('should update order-by references for any terms columns', () => { const field1 = 'foo'; const field2 = 'bar'; - const percentile = faker.random.number(100); + const percentile = faker.number.int(100); const aggs = [ makeEsAggBuilder('aggTerms', { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/chart_switch/chart_switch.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/chart_switch/chart_switch.test.tsx index 6795cd8caaa83..5686d94f52d49 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/chart_switch/chart_switch.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/chart_switch/chart_switch.test.tsx @@ -21,7 +21,7 @@ import { DatasourcePublicAPI, SuggestionRequest, DatasourceSuggestion } from '.. import { ChartSwitchProps } from './chart_switch'; import { ChartSwitchPopover } from './chart_switch_popover'; import { LensAppState, applyChanges } from '../../../../state_management'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; const mockFrame = (layers: string[]) => ({ ...createMockFramePublicAPI(), diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_header.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_header.test.tsx index 6f0edd6cbcd16..bcd21c71312ce 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_header.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_header.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { screen } from '@testing-library/react'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { createMockDatasource, createMockFramePublicAPI, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx index 9c3457dacc6d4..9cfb1597ffdd4 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx @@ -12,7 +12,7 @@ import { ChildDragDropProvider, Droppable, Draggable } from '@kbn/dom-drag-drop' import { FramePublicAPI, Visualization, VisualizationConfigProps } from '../../../types'; import { LayerPanel } from './layer_panel'; import { coreMock } from '@kbn/core/public/mocks'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { generateId } from '../../../id_generator'; import { createMockVisualization, @@ -144,7 +144,7 @@ describe('LayerPanel', () => { }; beforeEach(() => { - mockVisualization = createMockVisualization(faker.random.alphaNumeric()); + mockVisualization = createMockVisualization(faker.string.alphanumeric()); mockVisualization.getLayerIds.mockReturnValue(['first']); mockDatasource = createMockDatasource(); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 42abcdf8fe56c..e44e528e5a33c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -39,7 +39,7 @@ import { getLensInspectorService } from '../../../lens_inspector_service'; import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; import { disableAutoApply, enableAutoApply } from '../../../state_management/lens_slice'; import { Ast, toExpression } from '@kbn/interpreter'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; const defaultPermissions: Record>> = { navLinks: { management: true }, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx index 8694cc7c27dcf..c5cabaa053c4b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx @@ -18,7 +18,7 @@ import { updateVisualizationState, LensAppState } from '../../../state_managemen import { setChangesApplied } from '../../../state_management/lens_slice'; import { LensInspector } from '../../../lens_inspector_service'; import { screen } from '@testing-library/react'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { SettingsMenu } from '../../../app_plugin/settings_menu'; describe('workspace_panel_wrapper', () => { @@ -98,7 +98,7 @@ describe('workspace_panel_wrapper', () => { }); it('should render its children', async () => { - const customElementText = faker.random.word(); + const customElementText = faker.word.words(); renderWorkspacePanelWrapper({ children: {customElementText} }); expect(screen.getByText(customElementText)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index 54532360169fd..a4077b6919823 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -260,6 +260,7 @@ export function WorkspacePanelWrapper({ flexGrow: 0, height: '100%', width: '100%', + overflow: 'auto', ...visDimensionsCSS, }} > diff --git a/x-pack/plugins/lens/public/lens_ui_telemetry/color_telemetry_helpers.test.ts b/x-pack/plugins/lens/public/lens_ui_telemetry/color_telemetry_helpers.test.ts index 47eba8b0252ef..8719c54f6f1dd 100644 --- a/x-pack/plugins/lens/public/lens_ui_telemetry/color_telemetry_helpers.test.ts +++ b/x-pack/plugins/lens/public/lens_ui_telemetry/color_telemetry_helpers.test.ts @@ -13,7 +13,7 @@ import { DEFAULT_COLOR_MAPPING_CONFIG, DEFAULT_OTHER_ASSIGNMENT_INDEX, } from '@kbn/coloring'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; const exampleAssignment = ( valuesCount = 1, @@ -35,7 +35,7 @@ const exampleAssignment = ( return { rule: { type: 'matchExactly', - values: Array.from({ length: valuesCount }, () => faker.random.alpha()), + values: Array.from({ length: valuesCount }, () => faker.string.alpha()), }, color, touched: false, diff --git a/x-pack/plugins/lens/public/mocks/visualization_mock.tsx b/x-pack/plugins/lens/public/mocks/visualization_mock.tsx index f0513e66de0c5..9810b916d5ea6 100644 --- a/x-pack/plugins/lens/public/mocks/visualization_mock.tsx +++ b/x-pack/plugins/lens/public/mocks/visualization_mock.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; import { toExpression } from '@kbn/interpreter'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { Visualization, VisualizationMap } from '../types'; export function createMockVisualization( diff --git a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts index 0aed3edf70b89..64b7ca4501b08 100644 --- a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts +++ b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts @@ -226,7 +226,7 @@ export function loadEmbeddableData( handleEvent, disableTriggers, updateBlockingErrors, - renderCount: internalApi.renderCount$.getValue(), + getDisplayOptions: internalApi.getDisplayOptions, }), getUsedDataViews( currentState.attributes.references, diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts index e10dded4ad8f9..ff6206f3f70e4 100644 --- a/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts @@ -24,6 +24,7 @@ import { IndexPatternMap, IndexPatternRef, UserMessage, + VisualizationDisplayOptions, isLensFilterEvent, isLensMultiFilterEvent, isLensTableRowContextMenuClickEvent, @@ -61,7 +62,7 @@ interface GetExpressionRendererPropsParams { api: LensApi; addUserMessages: (messages: UserMessage[]) => void; updateBlockingErrors: (error: Error) => void; - renderCount: number; + getDisplayOptions: () => VisualizationDisplayOptions; } async function getExpressionFromDocument( @@ -146,7 +147,7 @@ export async function getExpressionRendererParams( addUserMessages, updateBlockingErrors, searchContext, - renderCount, + getDisplayOptions, }: GetExpressionRendererPropsParams ): Promise<{ params: ExpressionWrapperProps | null; @@ -215,7 +216,7 @@ export async function getExpressionRendererParams( variables: getVariables(api, state), style: state.style, className: state.className, - noPadding: state.noPadding, + noPadding: getDisplayOptions().noPadding, }; return { indexPatterns, diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts index dfddfe84b57cc..aba94db03de88 100644 --- a/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts @@ -9,7 +9,7 @@ import { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; import { getLensApiMock, getLensRuntimeStateMock, makeEmbeddableServices } from '../mocks'; import { LensApi, LensEmbeddableStartServices, LensPublicCallbacks } from '../types'; import { prepareEventHandler } from './on_event'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { LENS_EDIT_PAGESIZE_ACTION, LENS_EDIT_RESIZE_ACTION, @@ -109,7 +109,7 @@ describe('Embeddable interaction event handlers', () => { const event = { name: 'filter', data: { - data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + data: [{ value: faker.number.int(), row: 1, column: 'test', table: getTable() }], }, }; const { callbacks } = await submitEvent(event); @@ -119,7 +119,7 @@ describe('Embeddable interaction event handlers', () => { const event = { name: 'filter', data: { - data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + data: [{ value: faker.number.int(), row: 1, column: 'test', table: getTable() }], }, }; const { getTrigger } = await submitEvent(event, true); @@ -171,7 +171,7 @@ describe('Embeddable interaction event handlers', () => { await reSubmit({ name: 'filter', data: { - data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + data: [{ value: faker.number.int(), row: 1, column: 'test', table: getTable() }], }, }); diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts index a4f84c329bd3c..016bc0e87f11d 100644 --- a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts @@ -6,7 +6,7 @@ */ import { pick } from 'lodash'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import type { LensRuntimeState, VisualizationContext } from '../types'; import { initializeActionApi } from './initialize_actions'; import { @@ -42,7 +42,7 @@ function setupActionsApi( visOverrides: { id: 'lnsXY' }, dataOverrides: { id: 'form_based' }, }); - const uuid = faker.random.uuid(); + const uuid = faker.string.uuid(); const runtimeState = getLensRuntimeStateMock(stateOverrides); const apiMock = getLensApiMock(); diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts index 2a0c469b3bbfb..af68f887bff54 100644 --- a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts @@ -9,7 +9,7 @@ import type { LensRuntimeState } from '../types'; import { getLensRuntimeStateMock, getLensInternalApiMock, makeEmbeddableServices } from '../mocks'; import { initializeStateManagement } from './initialize_state_management'; import { initializeDashboardServices } from './initialize_dashboard_services'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { createEmptyLensState } from '../helper'; function setupDashboardServicesApi(runtimeOverrides?: Partial) { @@ -30,7 +30,7 @@ function setupDashboardServicesApi(runtimeOverrides?: Partial) describe('Transformation API', () => { it("should not save to library if there's already a saveObjectId", async () => { - const api = setupDashboardServicesApi({ savedObjectId: faker.random.uuid() }); + const api = setupDashboardServicesApi({ savedObjectId: faker.string.uuid() }); expect(await api.canLinkToLibrary()).toBe(false); }); diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts index d030a92a02b59..67a5d3a89a1c2 100644 --- a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts @@ -16,7 +16,7 @@ import { getUnchangingComparator, initializeTitles, } from '@kbn/presentation-publishing'; -import { apiPublishesSettings } from '@kbn/presentation-containers'; +import { apiIsPresentationContainer, apiPublishesSettings } from '@kbn/presentation-containers'; import { buildObservableVariable, isTextBasedLanguage } from '../helper'; import type { LensComponentProps, @@ -27,6 +27,7 @@ import type { LensSharedProps, IntegrationCallbacks, LensInternalApi, + LensApi, } from '../types'; import { apiHasLensComponentProps } from '../type_guards'; import { StateManagementConfig } from './initialize_state_management'; @@ -39,9 +40,12 @@ export interface DashboardServicesConfig { PublishesWritablePanelDescription & HasInPlaceLibraryTransforms & HasLibraryTransforms & + Pick & Pick; serialize: () => SerializedProps; - comparators: StateComparators; + comparators: StateComparators< + SerializedProps & Pick & { isNewPanel?: boolean } + >; cleanup: () => void; } @@ -78,6 +82,7 @@ export function initializeDashboardServices( return { api: { + parentApi: apiIsPresentationContainer(parentApi) ? parentApi : undefined, defaultPanelTitle: defaultPanelTitle$, defaultPanelDescription: defaultPanelDescription$, ...titlesApi, @@ -142,7 +147,7 @@ export function initializeDashboardServices( }, }, serialize: () => { - const { style, noPadding, className } = apiHasLensComponentProps(parentApi) + const { style, className } = apiHasLensComponentProps(parentApi) ? parentApi : ({} as LensComponentProps); const settings = apiPublishesSettings(parentApi) @@ -155,7 +160,6 @@ export function initializeDashboardServices( return { ...serializeTitles(), style, - noPadding, className, ...settings, palette: initialState.palette, @@ -179,6 +183,7 @@ export function initializeDashboardServices( overrides: overridesComparator, disableTriggers: disabledTriggersComparator, isNewPanel: getUnchangingComparator<{ isNewPanel?: boolean }, 'isNewPanel'>(), + parentApi: getUnchangingComparator, 'parentApi'>(), }, cleanup: noop, }; diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts index 2bdc00b3124a2..e366c24a6c0e0 100644 --- a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts @@ -6,21 +6,25 @@ */ import { BehaviorSubject } from 'rxjs'; +import { initializeTitles } from '@kbn/presentation-publishing'; import type { DataView } from '@kbn/data-views-plugin/common'; import { buildObservableVariable, createEmptyLensState } from '../helper'; import type { ExpressionWrapperProps, + LensEmbeddableStartServices, LensInternalApi, LensOverrides, LensRuntimeState, } from '../types'; -import { apiHasAbortController } from '../type_guards'; +import { apiHasAbortController, apiHasLensComponentProps } from '../type_guards'; import type { UserMessage } from '../../types'; export function initializeInternalApi( initialState: LensRuntimeState, - parentApi: unknown + parentApi: unknown, + { visualizationMap }: LensEmbeddableStartServices ): LensInternalApi { + const { titlesApi } = initializeTitles(initialState); const [hasRenderCompleted$] = buildObservableVariable(false); const [expressionParams$] = buildObservableVariable(null); const expressionAbortController$ = new BehaviorSubject(undefined); @@ -87,5 +91,30 @@ export function initializeInternalApi( validationMessages$.next([]); }, setAsCreated: () => isNewlyCreated$.next(false), + getDisplayOptions: () => { + const latestAttributes = attributes$.getValue(); + if (!latestAttributes.visualizationType) { + return {}; + } + + let displayOptions = + visualizationMap[latestAttributes.visualizationType]?.getDisplayOptions?.() ?? {}; + + if (apiHasLensComponentProps(parentApi) && parentApi.noPadding != null) { + displayOptions = { + ...displayOptions, + noPadding: parentApi.noPadding, + }; + } + + if (displayOptions.noPanelTitle == null && titlesApi.hidePanelTitle?.getValue()) { + displayOptions = { + ...displayOptions, + noPanelTitle: true, + }; + } + + return displayOptions; + }, }; } diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts index af5ecddecd2b4..1bf7853c0b261 100644 --- a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts @@ -11,6 +11,7 @@ import { type PublishesDataViews, type PublishesSavedObjectId, type StateComparators, + type PublishesRendered, } from '@kbn/presentation-publishing'; import { noop } from 'lodash'; import type { DataView } from '@kbn/data-views-plugin/common'; @@ -24,6 +25,7 @@ export interface StateManagementConfig { PublishesSavedObjectId & PublishesDataViews & PublishesDataLoading & + PublishesRendered & PublishesBlockingError; serialize: () => Pick; comparators: StateComparators< @@ -53,6 +55,7 @@ export function initializeStateManagement( const [dataViews$] = buildObservableVariable(internalApi.dataViews); const [dataLoading$] = buildObservableVariable(internalApi.dataLoading$); + const [rendered$] = buildObservableVariable(internalApi.hasRenderCompleted$); const [abortController$, abortControllerComparator] = buildObservableVariable< AbortController | undefined >(internalApi.expressionAbortController$); @@ -70,6 +73,7 @@ export function initializeStateManagement( dataViews: dataViews$, dataLoading: dataLoading$, blockingError: blockingError$, + rendered$, }, serialize: () => { return { diff --git a/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx b/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx index 8c17063f97a2e..074ae451115b5 100644 --- a/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx @@ -59,7 +59,7 @@ export const createLensEmbeddableFactory = ( * Observables and functions declared here are used internally to store mutating state values * This is an internal API not exposed outside of the embeddable. */ - const internalApi = initializeInternalApi(initialState, parentApi); + const internalApi = initializeInternalApi(initialState, parentApi, services); const visualizationContextHelper = initializeVisualizationContext(internalApi); diff --git a/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx index a3992e504c4df..ca8f489a711aa 100644 --- a/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx @@ -8,7 +8,7 @@ import { BehaviorSubject, Subject } from 'rxjs'; import deepMerge from 'deepmerge'; import React from 'react'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { Query, Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; import { PhaseEvent, ViewMode } from '@kbn/presentation-publishing'; import { DataView } from '@kbn/data-views-plugin/common'; @@ -49,7 +49,7 @@ import { const LensApiMock: LensApi = { // Static props type: DOC_TYPE, - uuid: faker.random.uuid(), + uuid: faker.string.uuid(), // Shared Embeddable Observables panelTitle: new BehaviorSubject(faker.lorem.words()), hidePanelTitle: new BehaviorSubject(false), @@ -94,7 +94,7 @@ const LensApiMock: LensApi = { setPanelTitle: jest.fn(), setHidePanelTitle: jest.fn(), phase$: new BehaviorSubject({ - id: faker.random.uuid(), + id: faker.string.uuid(), status: 'rendered', timeToEvent: 1000, }), @@ -115,6 +115,7 @@ const LensApiMock: LensApi = { viewMode: new BehaviorSubject('view'), disabledActionIds: new BehaviorSubject(undefined), setDisabledActionIds: jest.fn(), + rendered$: new BehaviorSubject(false), }; const LensSerializedStateMock: LensSerializedState = createEmptyLensState( @@ -137,7 +138,7 @@ export function getLensApiMock(overrides: Partial = {}) { export function getLensSerializedStateMock(overrides: Partial = {}) { return { - savedObjectId: faker.random.uuid(), + savedObjectId: faker.string.uuid(), ...LensSerializedStateMock, ...overrides, }; @@ -308,6 +309,7 @@ const LensInternalApiMock: LensInternalApi = { dispatchError: jest.fn(), updateValidationMessages: jest.fn(), setAsCreated: jest.fn(), + getDisplayOptions: jest.fn(() => ({})), }; export function getLensInternalApiMock(overrides: Partial = {}): LensInternalApi { diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx index 04c3511ab3d4f..f444f429250ba 100644 --- a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx @@ -13,6 +13,12 @@ import { PublishingSubject } from '@kbn/presentation-publishing'; import React from 'react'; import { LensEmbeddableComponent } from './lens_embeddable_component'; +jest.mock('../expression_wrapper', () => ({ + ExpressionWrapper: () => ( +
        + ), +})); + type GetValueType = Type extends PublishingSubject ? X : never; function getDefaultProps({ @@ -39,4 +45,17 @@ describe('Lens Embeddable component', () => { render(); expect(screen.queryByTestId('lens-embeddable')).not.toBeInTheDocument(); }); + + it('shoud not render the title if the visualization forces the title to be hidden', () => { + const getDisplayOptions = jest.fn(() => ({ noPanelTitle: true })); + const props = getDefaultProps({ + internalApiOverrides: { + getDisplayOptions, + }, + }); + + render(); + expect(props.internalApi.getDisplayOptions).toHaveBeenCalled(); + expect(screen.getByTestId('lens-embeddable').parentElement).not.toHaveAttribute('data-title'); + }); }); diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx index 6d98b901d905f..122891788a808 100644 --- a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx @@ -29,18 +29,18 @@ export function LensEmbeddableComponent({ expressionParams, // used for functional tests renderCount, - // has the render completed? - hasRendered, // these are blocking errors that can be shown in a badge // without replacing the entire panel blockingErrors, + // has the render completed? + hasRendered, // has view mode changed? latestViewMode, ] = useBatchedPublishingSubjects( internalApi.expressionParams$, internalApi.renderCount$, - internalApi.hasRenderCompleted$, internalApi.validationMessages$, + api.rendered$, api.viewMode ); const canEdit = Boolean(api.isEditingEnabled?.() && getViewMode(latestViewMode) === 'edit'); @@ -57,7 +57,7 @@ export function LensEmbeddableComponent({ const rootRef = useDispatcher(hasRendered, api); // Publish the data attributes only if avaialble/visible - const title = api.hidePanelTitle?.getValue() + const title = internalApi.getDisplayOptions()?.noPanelTitle ? undefined : { 'data-title': api.panelTitle?.getValue() ?? api.defaultPanelTitle?.getValue() }; const description = api.panelDescription?.getValue() diff --git a/x-pack/plugins/lens/public/react_embeddable/types.ts b/x-pack/plugins/lens/public/react_embeddable/types.ts index 03a9801507d1c..c860c543570c1 100644 --- a/x-pack/plugins/lens/public/react_embeddable/types.ts +++ b/x-pack/plugins/lens/public/react_embeddable/types.ts @@ -17,6 +17,7 @@ import type { HasEditCapabilities, HasInPlaceLibraryTransforms, HasLibraryTransforms, + HasParentApi, HasSupportedTriggers, PublishesBlockingError, PublishesDataLoading, @@ -25,6 +26,7 @@ import type { PublishesSavedObjectId, PublishesUnifiedSearch, PublishesViewMode, + PublishesRendered, PublishesWritablePanelDescription, PublishesWritablePanelTitle, PublishingSubject, @@ -62,6 +64,7 @@ import type { AllowedGaugeOverrides } from '@kbn/expression-gauge-plugin/common' import type { AllowedPartitionOverrides } from '@kbn/expression-partition-vis-plugin/common'; import type { AllowedXYOverrides } from '@kbn/expression-xy-plugin/common'; import type { Action } from '@kbn/ui-actions-plugin/public'; +import { PresentationContainer } from '@kbn/presentation-containers'; import type { LegacyMetricState } from '../../common'; import type { LensDocument } from '../persistence'; import type { LensInspector } from '../lens_inspector_service'; @@ -80,6 +83,7 @@ import type { SharingSavedObjectProps, Simplify, UserMessage, + VisualizationDisplayOptions, VisualizationMap, } from '../types'; import type { LensPluginStartDependencies } from '../plugin'; @@ -275,7 +279,7 @@ export type LensSerializedState = Simplify< LensUnifiedSearchContext & LensPanelProps & SerializedTitles & - LensSharedProps & + Omit & Partial & { isNewPanel?: boolean } >; @@ -362,6 +366,8 @@ export type LensApi = Simplify< PublishesUnifiedSearch & // Let the container know the loading state PublishesDataLoading & + // Let the container know when the rendering has completed rendering + PublishesRendered & // Let the container know the used data views PublishesDataViews & // Let the container operate on panel title/description @@ -375,6 +381,8 @@ export type LensApi = Simplify< HasLibraryTransforms & // Let the container know the view mode PublishesViewMode & + // forward the parentApi, note that will be exposed only if it satisfy the PresentationContainer interface + Partial> & // Let the container know the saved object id PublishesSavedObjectId & // Lens specific API methods: @@ -411,6 +419,7 @@ export type LensInternalApi = Simplify< validationMessages$: PublishingSubject; updateValidationMessages: (newMessages: UserMessage[]) => void; resetAllMessages: () => void; + getDisplayOptions: () => VisualizationDisplayOptions; } >; diff --git a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx index 1514a508b8781..0a47af299d136 100644 --- a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx +++ b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx @@ -17,7 +17,7 @@ import { Location, History } from 'history'; import { act } from 'react-dom/test-utils'; import { InitialAppState, loadInitial } from './lens_slice'; import { Filter } from '@kbn/es-query'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DOC_TYPE } from '../../common/constants'; const history = { diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx index 14b3796fbd145..992e79681d415 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { fireEvent, render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { I18nProvider } from '@kbn/i18n-react'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { act } from 'react-dom/test-utils'; import { IFieldFormat } from '@kbn/field-formats-plugin/common'; import { coreMock } from '@kbn/core/public/mocks'; @@ -504,7 +504,7 @@ describe('DatatableComponent', () => { data.rows = new Array(rowNumbers).fill({ a: 'shoes', b: 1588024800000, - c: faker.random.number(), + c: faker.number.int(), }); args.pageSize = pageSize; @@ -537,7 +537,7 @@ describe('DatatableComponent', () => { data.rows = new Array(rowNumbers).fill({ a: 'shoes', b: 1588024800000, - c: faker.random.number(), + c: faker.number.int(), }); args.pageSize = pageSize; @@ -558,7 +558,7 @@ describe('DatatableComponent', () => { data.rows = new Array(20).fill({ a: 'shoes', b: 1588024800000, - c: faker.random.number(), + c: faker.number.int(), }); renderDatatableComponent({ args, @@ -584,7 +584,7 @@ describe('DatatableComponent', () => { data.rows = new Array(rowNumbers).fill({ a: 'shoes', b: 1588024800000, - c: faker.random.number(), + c: faker.number.int(), }); args.pageSize = pageSize; @@ -624,7 +624,7 @@ describe('DatatableComponent', () => { data.rows = new Array(rowNumbers).fill({ a: 'shoes', b: 1588024800000, - c: faker.random.number(), + c: faker.number.int(), }); args.pageSize = pageSize; diff --git a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx index 73f07d66bcb8b..7a143d3c9ba8a 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import userEvent from '@testing-library/user-event'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { euiLightVars } from '@kbn/ui-theme'; @@ -77,7 +77,7 @@ describe('dimension editor', () => { id: 'first', rows: Array(3).fill({ 'metric-col-id': faker.lorem.word(3), - 'max-col-id': faker.random.number(), + 'max-col-id': faker.number.int(), }), }, ]), @@ -106,8 +106,8 @@ describe('dimension editor', () => { { id: 'first', rows: Array(3).fill({ - 'metric-col-id': faker.random.number(), - 'secondary-metric-col-id': faker.random.number(), + 'metric-col-id': faker.number.int(), + 'secondary-metric-col-id': faker.number.int(), }), }, ]), diff --git a/x-pack/plugins/ml/common/constants/alerts.ts b/x-pack/plugins/ml/common/constants/alerts.ts index 009345d23542d..8ed9d61b418ff 100644 --- a/x-pack/plugins/ml/common/constants/alerts.ts +++ b/x-pack/plugins/ml/common/constants/alerts.ts @@ -12,6 +12,7 @@ import { ALERT_RULE_NAME, ALERT_START, ALERT_STATUS, + AlertConsumers, ML_ANOMALY_DETECTION_RULE_TYPE_ID, } from '@kbn/rule-data-utils'; import type { JobsHealthTests } from '../types/alerts'; @@ -21,6 +22,9 @@ export const ML_ALERT_TYPES = { AD_JOBS_HEALTH: 'xpack.ml.anomaly_detection_jobs_health', } as const; +export const ML_RULE_TYPE_IDS = Object.values(ML_ALERT_TYPES); +export const ML_VALID_CONSUMERS = [AlertConsumers.ML, AlertConsumers.ALERTS]; + export type MlAlertType = (typeof ML_ALERT_TYPES)[keyof typeof ML_ALERT_TYPES]; export const ALERT_PREVIEW_SAMPLE_SIZE = 5; diff --git a/x-pack/plugins/ml/common/constants/trained_models.ts b/x-pack/plugins/ml/common/constants/trained_models.ts new file mode 100644 index 0000000000000..c6092037cbfb4 --- /dev/null +++ b/x-pack/plugins/ml/common/constants/trained_models.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Default page for the trained_models endpoint is 100, + * which is too small for the most cases, so we set it to 10000. + */ +export const DEFAULT_TRAINED_MODELS_PAGE_SIZE = 10000; diff --git a/x-pack/plugins/ml/common/index.ts b/x-pack/plugins/ml/common/index.ts index bc53fc4247f2d..dbb6c1a54ca16 100644 --- a/x-pack/plugins/ml/common/index.ts +++ b/x-pack/plugins/ml/common/index.ts @@ -8,5 +8,5 @@ export { getDefaultCapabilities as getDefaultMlCapabilities } from './types/capabilities'; export { DATAFEED_STATE, JOB_STATE } from './constants/states'; export type { MlSummaryJob, SummaryJobState } from './types/anomaly_detection_jobs'; -export { ML_ALERT_TYPES } from './constants/alerts'; +export { ML_ALERT_TYPES, ML_RULE_TYPE_IDS } from './constants/alerts'; export type { Job, Datafeed } from './types/anomaly_detection_jobs'; diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index e7a097fae7dc4..b598a3bfd4d2d 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -6,6 +6,7 @@ */ import type { KibanaRequest } from '@kbn/core/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { PLUGIN_ID } from '../constants/app'; import { ML_JOB_SAVED_OBJECT_TYPE, @@ -109,6 +110,11 @@ export function getDefaultCapabilities(): MlCapabilities { }; } +const alertingFeatures = Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID, ALERTING_FEATURE_ID], +})); + export function getPluginPrivileges() { const apmUserMlCapabilitiesKeys = Object.keys(apmUserMlCapabilities); const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); @@ -150,10 +156,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - all: Object.values(ML_ALERT_TYPES), + all: alertingFeatures, }, alert: { - all: Object.values(ML_ALERT_TYPES), + all: alertingFeatures, }, }, }, @@ -172,10 +178,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - read: Object.values(ML_ALERT_TYPES), + read: alertingFeatures, }, alert: { - read: Object.values(ML_ALERT_TYPES), + read: alertingFeatures, }, }, }, diff --git a/x-pack/plugins/ml/common/types/trained_models.ts b/x-pack/plugins/ml/common/types/trained_models.ts index 794d3123eee7f..f4ed52ff21f52 100644 --- a/x-pack/plugins/ml/common/types/trained_models.ts +++ b/x-pack/plugins/ml/common/types/trained_models.ts @@ -193,6 +193,7 @@ export interface AllocatedModel { */ model_id?: string; state: string; + reason?: string; model_size_bytes: number; required_native_memory_bytes: number; node: { diff --git a/x-pack/plugins/ml/kibana.jsonc b/x-pack/plugins/ml/kibana.jsonc index 274a92c57a2c3..5c4961de54e97 100644 --- a/x-pack/plugins/ml/kibana.jsonc +++ b/x-pack/plugins/ml/kibana.jsonc @@ -63,7 +63,8 @@ "lens", "maps", "savedObjectsFinder", - "usageCollection" + "usageCollection", + "alerting" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx index d06c46cc6f71e..01f4d2d7be74f 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx @@ -60,6 +60,7 @@ export const LogRateAnalysisPage: FC = () => { 'unifiedSearch', 'observabilityAIAssistant', 'embeddable', + 'cases', ]), }} /> diff --git a/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx b/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx index b9b680a9fbac5..338c5a2a2b3c5 100644 --- a/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx +++ b/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx @@ -15,9 +15,12 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ALERT_STATUS_ACTIVE, AlertConsumers, type AlertStatus } from '@kbn/rule-data-utils'; +import { ALERT_STATUS_ACTIVE, type AlertStatus } from '@kbn/rule-data-utils'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import React, { type FC, useState } from 'react'; import useObservable from 'react-use/lib/useObservable'; +import { ML_VALID_CONSUMERS } from '../../../../common/constants/alerts'; +import { ML_RULE_TYPE_IDS } from '../../../../common'; import { ML_ALERTS_CONFIG_ID } from '../../../alerting/anomaly_detection_alerts_table/register_alerts_table_configuration'; import { CollapsiblePanel } from '../../components/collapsible_panel'; import { useMlKibana } from '../../contexts/kibana'; @@ -42,13 +45,13 @@ export const AlertsPanel: FC = () => { const alertsQuery = useObservable(anomalyDetectionAlertsStateService.alertsQuery$, {}); const isLoading = useObservable(anomalyDetectionAlertsStateService.isLoading$, true); - const alertStateProps = { + const alertStateProps: AlertsTableStateProps = { alertsTableConfigurationRegistry: triggersActionsUi!.alertsTableConfigurationRegistry, configurationId: ML_ALERTS_CONFIG_ID, id: `ml-details-alerts`, - featureIds: [AlertConsumers.ML], + ruleTypeIds: ML_RULE_TYPE_IDS, + consumers: ML_VALID_CONSUMERS, query: alertsQuery, - showExpandToDetails: true, showAlertStatusWithFlapping: true, cellContext: { fieldFormats, diff --git a/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts b/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts index d02e9baf91c95..82bd60a4802ab 100644 --- a/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts +++ b/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts @@ -21,7 +21,6 @@ import { ALERT_START, ALERT_STATUS, ALERT_UUID, - AlertConsumers, } from '@kbn/rule-data-utils'; import { isDefined } from '@kbn/ml-is-defined'; import { getSeverityColor } from '@kbn/ml-anomaly-utils'; @@ -30,6 +29,8 @@ import { ALERT_ANOMALY_SCORE, ALERT_ANOMALY_TIMESTAMP, ML_ALERT_TYPES, + ML_RULE_TYPE_IDS, + ML_VALID_CONSUMERS, } from '../../../../common/constants/alerts'; import { StateService } from '../../services/state_service'; import type { AnomalyTimelineStateService } from '../anomaly_timeline_state_service'; @@ -175,7 +176,8 @@ export class AnomalyDetectionAlertsStateService extends StateService { return this.data.search .search( { - featureIds: [AlertConsumers.ML], + ruleTypeIds: ML_RULE_TYPE_IDS, + consumers: ML_VALID_CONSUMERS, query, }, { strategy: 'privateRuleRegistryAlertsSearchStrategy' } diff --git a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx index 4dd04780e2e92..cc9beceff5556 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx @@ -57,15 +57,17 @@ export const AllocatedModels: FC = ({ { width: '8%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelRoutingStateHeader', { - defaultMessage: 'Routing state', + defaultMessage: 'State', }), 'data-test-subj': 'mlAllocatedModelsTableRoutingState', render: (v: AllocatedModel) => { const { routing_state: routingState, reason } = v.node.routing_state; + const isFailed = routingState === 'failed'; + return ( - {routingState} + {routingState} ); }, @@ -252,7 +254,7 @@ export const AllocatedModels: FC = ({ }), 'data-test-subj': 'mlAllocatedModelsTableStartedTime', render: (v: AllocatedModel) => { - return dateFormatter(v.node.start_time); + return v.node.start_time ? dateFormatter(v.node.start_time) : '-'; }, }, { diff --git a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx index f7e95e3eda52c..f44dc55dab2df 100644 --- a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx @@ -169,13 +169,40 @@ export const ExpandedRow: FC = ({ item }) => { license_level, ]); - const deploymentStatItems: AllocatedModel[] = useMemo(() => { + const deploymentStatItems = useMemo(() => { const deploymentStats = stats.deployment_stats; const modelSizeStats = stats.model_size_stats; if (!deploymentStats || !modelSizeStats) return []; - const items: AllocatedModel[] = deploymentStats.flatMap((perDeploymentStat) => { + return deploymentStats.flatMap((perDeploymentStat) => { + // A deployment can be in a starting state and not allocated to any node yet. + if (perDeploymentStat.nodes.length < 1) { + return [ + { + key: `${perDeploymentStat.deployment_id}_no_node`, + ...perDeploymentStat, + ...modelSizeStats, + node: { + name: '-', + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: perDeploymentStat.state, + reason: perDeploymentStat.reason, + }, + last_access: 0, + number_of_pending_requests: 0, + start_time: 0, + throughput_last_minute: 0, + number_of_allocations: 0, + threads_per_allocation: 0, + error_count: 0, + }, + }, + ]; + } + return perDeploymentStat.nodes.map((n) => { const nodeName = Object.values(n.node)[0].name; return { @@ -201,8 +228,6 @@ export const ExpandedRow: FC = ({ item }) => { }; }); }); - - return items; }, [stats]); const hideColumns = useMemo(() => { diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts index 4e112a2ff313b..e720f12fa4dd5 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts @@ -20,6 +20,7 @@ import { } from '@kbn/ml-data-frame-analytics-utils'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; +import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../../common/constants/trained_models'; import type { MlFeatures } from '../../../common/constants/app'; import type { ModelService } from '../model_management/models_provider'; import { modelsProvider } from '../model_management'; @@ -38,7 +39,6 @@ import { isTransformLinkReturnType, } from './types'; import type { MlClient } from '../../lib/ml_client'; -import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../routes/trained_models'; export class AnalyticsManager { private _trainedModels: estypes.MlTrainedModelConfig[] = []; diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 01f3ec7e5d131..ba6c5387a93cb 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -26,6 +26,7 @@ import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import type { CasesServerSetup } from '@kbn/cases-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import type { PluginsSetup, PluginsStart, RouteInitialization } from './types'; import type { MlCapabilities } from '../common/types/capabilities'; @@ -142,7 +143,10 @@ export class MlServerPlugin management: { insightsAndAlerting: ['jobsListLink', 'triggersActions'], }, - alerting: Object.values(ML_ALERT_TYPES), + alerting: Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID, ALERTING_FEATURE_ID], + })), privileges: { all: admin, read: user, diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 3814d36bc3a6c..8c9f90db38186 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -135,7 +135,7 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const rulesClient = alerting?.getRulesClient(); + const rulesClient = await alerting?.getRulesClient(); const { deleteJobs } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds, deleteUserAnnotations, deleteAlertingRules } = request.body; @@ -283,7 +283,8 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const { jobsSummary } = jobServiceProvider(client, mlClient, alerting?.getRulesClient()); + const rulesClient = await alerting?.getRulesClient(); + const { jobsSummary } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds } = request.body; const resp = await jobsSummary(jobIds); @@ -317,11 +318,8 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response, context }) => { try { const alerting = await context.alerting; - const { getJobIdsWithGeo } = jobServiceProvider( - client, - mlClient, - alerting?.getRulesClient() - ); + const rulesClient = await alerting?.getRulesClient(); + const { getJobIdsWithGeo } = jobServiceProvider(client, mlClient, rulesClient); const resp = await getJobIdsWithGeo(); @@ -425,11 +423,9 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const { createFullJobsList } = jobServiceProvider( - client, - mlClient, - alerting?.getRulesClient() - ); + const rulesClient = await alerting?.getRulesClient(); + + const { createFullJobsList } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds } = request.body; const resp = await createFullJobsList(jobIds); diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index c0010777ecf18..2782c4be18207 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -17,6 +17,7 @@ import type { } from '@kbn/ml-trained-models-utils'; import { isDefined } from '@kbn/ml-is-defined'; import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../common/constants/trained_models'; import { type MlFeatures, ML_INTERNAL_BASE_PATH } from '../../common/constants/app'; import type { RouteInitialization } from '../types'; import { wrapError } from '../client/error_wrapper'; @@ -44,8 +45,6 @@ import { mlLog } from '../lib/log'; import { forceQuerySchema } from './schemas/anomaly_detectors_schema'; import { modelsProvider } from '../models/model_management'; -export const DEFAULT_TRAINED_MODELS_PAGE_SIZE = 10000; - export function filterForEnabledFeatureModels< T extends TrainedModelConfigResponse | estypes.MlTrainedModelConfig >(models: T[], enabledFeatures: MlFeatures) { diff --git a/x-pack/plugins/ml/server/saved_objects/util.ts b/x-pack/plugins/ml/server/saved_objects/util.ts index 27562e919b79f..7f3f087ea61be 100644 --- a/x-pack/plugins/ml/server/saved_objects/util.ts +++ b/x-pack/plugins/ml/server/saved_objects/util.ts @@ -12,6 +12,7 @@ import { type IScopedClusterClient, SavedObjectsClient, } from '@kbn/core/server'; +import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../common/constants/trained_models'; import type { TrainedModelJob, MLSavedObjectService } from './service'; import { ML_JOB_SAVED_OBJECT_TYPE } from '../../common/types/saved_objects'; @@ -86,7 +87,9 @@ export function mlFunctionsFactory(client: IScopedClusterClient) { }, async getTrainedModels() { try { - return await client.asInternalUser.ml.getTrainedModels(); + return await client.asInternalUser.ml.getTrainedModels({ + size: DEFAULT_TRAINED_MODELS_PAGE_SIZE, + }); } catch (error) { return null; } diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index 25b22722a33b4..89dcba5637787 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -151,11 +151,6 @@ export const METRICBEAT_INDEX_NAME_UNIQUE_TOKEN = '-mb-'; // We use this for metricbeat migration to identify specific products that we do not have constants for export const ELASTICSEARCH_SYSTEM_ID = 'elasticsearch'; -/** - * The id of the infra source owned by the monitoring plugin. - */ -export const INFRA_SOURCE_ID = 'internal-stack-monitoring'; - /* * These constants represent code paths within `getClustersFromRequest` * that an api call wants to invoke. This is meant as an optimization to diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts b/x-pack/plugins/monitoring/common/get_index_patterns.test.ts similarity index 98% rename from x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts rename to x-pack/plugins/monitoring/common/get_index_patterns.test.ts index c13217ab0abc6..7727d5e04916a 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts +++ b/x-pack/plugins/monitoring/common/get_index_patterns.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { DS_INDEX_PATTERN_TYPES } from '../../../common/constants'; -import { MonitoringConfig } from '../..'; +import { DS_INDEX_PATTERN_TYPES } from './constants'; +import { MonitoringConfig } from '../server'; import { getElasticsearchDataset, getKibanaDataset, diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts b/x-pack/plugins/monitoring/common/get_index_patterns.ts similarity index 96% rename from x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts rename to x-pack/plugins/monitoring/common/get_index_patterns.ts index 4f293baf613bf..d0f19e622eedf 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts +++ b/x-pack/plugins/monitoring/common/get_index_patterns.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { prefixIndexPatternWithCcs } from '../../../common/ccs_utils'; +import { prefixIndexPatternWithCcs } from './ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH, INDEX_PATTERN_ELASTICSEARCH_ECS, @@ -16,8 +16,8 @@ import { DS_INDEX_PATTERN_METRICS, INDEX_PATTERN_TYPES, INDEX_PATTERN_ENTERPRISE_SEARCH, -} from '../../../common/constants'; -import { MonitoringConfig } from '../../config'; +} from './constants'; +import type { MonitoringConfig } from '../server/config'; interface CommonIndexPatternArgs { config: MonitoringConfig; diff --git a/x-pack/plugins/monitoring/kibana.jsonc b/x-pack/plugins/monitoring/kibana.jsonc index 5b9b2853357b9..334ffd05890bc 100644 --- a/x-pack/plugins/monitoring/kibana.jsonc +++ b/x-pack/plugins/monitoring/kibana.jsonc @@ -26,7 +26,6 @@ ], "optionalPlugins": [ "infra", - "logsShared", "usageCollection", "home", "cloud", @@ -41,7 +40,6 @@ "kibanaUtils", "alerting", "kibanaReact", - "logsShared" ] } } \ No newline at end of file diff --git a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx index 2cca4638876c9..f1e84753820fe 100644 --- a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx +++ b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx @@ -270,6 +270,7 @@ describe('alert_form', () => { actionTypeRegistry={actionTypeRegistry} featureId="alerting" producerId="alerting" + ruleTypeId=".es-query" /> diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap index a3d5e96d6ef2f..91b3dea5ab049 100644 --- a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap @@ -12,10 +12,8 @@ exports[`Logs should render a link to filter by cluster uuid 1`] = ` id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": - Logs + "link": + Discover , } } @@ -36,10 +34,8 @@ exports[`Logs should render a link to filter by cluster uuid and index uuid 1`] id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": - Logs + "link": + Discover , } } @@ -60,10 +56,8 @@ exports[`Logs should render a link to filter by cluster uuid and node uuid 1`] = id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": - Logs + "link": + Discover , } } @@ -290,10 +284,8 @@ exports[`Logs should render normally 1`] = ` id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": - Logs + "link": + Discover , } } diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.js b/x-pack/plugins/monitoring/public/components/logs/logs.js index 3da4bc9dc13ff..82fdac6ea1f0d 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.js @@ -5,7 +5,7 @@ * 2.0. */ -import React, { PureComponent } from 'react'; +import React, { PureComponent, useContext } from 'react'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { upperFirst } from 'lodash'; import { Legacy } from '../../legacy_shims'; @@ -15,7 +15,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { Reason } from './reason'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; +import { ExternalConfigContext } from '../../application/contexts/external_config_context'; const getFormattedDateTimeLocal = (timestamp) => { const timezone = Legacy.shims.uiSettings?.get('dateFormat:tz'); @@ -111,7 +111,7 @@ const clusterColumns = [ }, ]; -function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin) { +function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices) { const params = []; if (clusterUuid) { params.push(`elasticsearch.cluster.uuid:${clusterUuid}`); @@ -124,10 +124,17 @@ function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin) { } const filter = params.join(' and '); - const { logsLocator } = getLogsLocatorsFromUrlService(sharePlugin.url); + const discoverLocator = sharePlugin.url.locators.get('DISCOVER_APP_LOCATOR'); - const base = logsLocator.getRedirectUrl({ - filter, + const base = discoverLocator.getRedirectUrl({ + dataViewSpec: { + id: logsIndices, + title: logsIndices, + }, + query: { + language: 'kuery', + query: filter, + }, }); return base; @@ -137,7 +144,8 @@ export const Logs = (props) => { const { services: { share }, } = useKibana(); - return ; + const externalConfig = useContext(ExternalConfigContext); + return ; }; export class LogsContent extends PureComponent { renderLogs() { @@ -168,13 +176,15 @@ export class LogsContent extends PureComponent { renderCallout() { const { capabilities: uiCapabilities, infra, kibanaServices } = Legacy.shims; - const show = uiCapabilities.logs && uiCapabilities.logs.show; + const show = uiCapabilities.discover && uiCapabilities.discover.show; + const { logs: { enabled }, nodeId, clusterUuid, indexUuid, sharePlugin, + logsIndices, } = this.props; if (!enabled || !show) { @@ -195,9 +205,11 @@ export class LogsContent extends PureComponent { defaultMessage="Visit {link} to dive deeper." values={{ link: ( - + {i18n.translate('xpack.monitoring.logs.listing.calloutLinkText', { - defaultMessage: 'Logs', + defaultMessage: 'Discover', })} ), diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.test.js b/x-pack/plugins/monitoring/public/components/logs/logs.test.js index 1117a484a294c..9d3f68c854505 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.test.js @@ -10,32 +10,26 @@ import { shallow } from 'enzyme'; import { LogsContent } from './logs'; import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; -const sharePlugin = sharePluginMock.createStartContract(); - -jest.mock('@kbn/logs-shared-plugin/common', () => { - return { - getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({ - logsLocator: { getRedirectUrl: jest.fn(() => '') }, - }), - }; -}); - jest.mock('../../legacy_shims', () => ({ Legacy: { shims: { getBasePath: () => '', - capabilities: { logs: { show: true } }, - infra: { - locators: { - logsLocator: { - getRedirectUrl: () => '', - }, - }, - }, + capabilities: { discover: { show: true } }, + infra: {}, }, }, })); +const sharePlugin = { + url: { + locators: { + get: () => { + return sharePluginMock.createLocator(); + }, + }, + }, +}; + const logs = { enabled: true, limit: 10, @@ -134,39 +128,69 @@ const logs = { describe('Logs', () => { it('should render normally', () => { - const component = shallow(); + const component = shallow( + + ); expect(component).toMatchSnapshot(); }); it('should render fewer columns for node or index view', () => { - const component = shallow(); + const component = shallow( + + ); expect(component.find('EuiBasicTable').prop('columns')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid', () => { const component = shallow( - + ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid and node uuid', () => { const component = shallow( - + ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid and index uuid', () => { const component = shallow( - + ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a reason if the logs are disabled', () => { const component = shallow( - + ); expect(component).toMatchSnapshot(); }); diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts index e29faa9ca5d86..02033d839e1ae 100644 --- a/x-pack/plugins/monitoring/public/plugin.ts +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -19,6 +19,7 @@ import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public'; import { + CCS_REMOTE_PATTERN, RULE_DETAILS, RULE_THREAD_POOL_SEARCH_REJECTIONS, RULE_THREAD_POOL_WRITE_REJECTIONS, @@ -38,6 +39,7 @@ import { MonitoringStartPluginDependencies, LegacyMonitoringStartPluginDependencies, } from './types'; +import { getIndexPatterns } from '../common/get_index_patterns'; interface MonitoringSetupPluginDependencies { home?: HomePublicPluginSetup; @@ -154,6 +156,7 @@ export class MonitoringPlugin monitoring.ui.kibana.reporting.stale_status_threshold_seconds, ], ['isCcsEnabled', monitoring.ui.ccs.enabled], + ['logsIndices', getLogsIndices(monitoring)], ]; } @@ -188,3 +191,11 @@ export class MonitoringPlugin } } } + +const getLogsIndices = (config: MonitoringConfig) => { + return getIndexPatterns({ + config, + type: 'logs', + ccs: CCS_REMOTE_PATTERN, + }); +}; diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts index f39af9fffe7d6..24062f0b947a0 100644 --- a/x-pack/plugins/monitoring/server/index.ts +++ b/x-pack/plugins/monitoring/server/index.ts @@ -35,6 +35,7 @@ export const config: PluginConfigDescriptor> = { stale_status_threshold_seconds: true, }, }, + logs: true, }, kibana: true, }, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts index f7535c26f2e43..50cc76225f418 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { isCCSRemoteIndexName } from '@kbn/es-query'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; import { CCRReadExceptionsStats } from '../../../common/types/alerts'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts index a4ef0b1321fa7..1d35440d65ae3 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertClusterHealth } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; export async function fetchClusterHealth( diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts index 80b1128ddf162..870d1dde9e4ca 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts @@ -8,7 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { get } from 'lodash'; import { AlertCluster } from '../../../common/types/alerts'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts index b74b1b78b495b..761d3087d8c73 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts @@ -11,7 +11,7 @@ import moment from 'moment'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../common/constants'; import { AlertCluster, AlertCpuUsageNodeStats } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts index 7bf405985e57b..1c8f9808a04a5 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertDiskUsageNodeStats } from '../../../common/types/ale import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchDiskUsageNodeStats( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts index 4c5f6b06d39e4..a82cb77c047af 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchElasticsearchVersions( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts index 5c32794cbf212..7b5affc78702a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts @@ -12,7 +12,7 @@ import { ESGlobPatterns, RegExPatterns } from '../../../common/es_glob_patterns' import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; type TopHitType = ElasticsearchResponseHit & { _source: { index_stats?: Partial }; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts index bd6f7d3255abf..3f6282c049aa7 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; interface ESAggResponse { key: string; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts index 30c1317696d7e..b7216b259302a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchLicenses( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts index 2d4223091051b..5bbaf32442694 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; interface ESAggResponse { key: string; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts index 4d05843c6703c..da943945aebce 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertMemoryUsageNodeStats } from '../../../common/types/a import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchMemoryUsageNodeStats( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index 35f37c14b98ac..5343604011710 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { AlertCluster, AlertMissingData } from '../../../common/types/alerts'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; interface ClusterBucketESResponse { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts index cb8f0e4e14b82..f4cf1f5cb4f7a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; function formatNode( nodes: NonNullable['nodes']> | undefined diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts index 0cf69df44a181..3e26d9eb77028 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertThreadPoolRejectionsStats } from '../../../common/ty import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; const invalidNumberValue = (value: number) => { return isNaN(value) || value === undefined || value === null; diff --git a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts index 85958eccfe2d4..1929f5c695314 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts @@ -7,7 +7,7 @@ import { ApmMetric, ApmMetricFields } from '../metrics'; import { createQuery } from '../create_query'; -import { getBeatDataset } from '../cluster/get_index_patterns'; +import { getBeatDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all APM instances. diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts index 072f296fc52a3..5764d787142c9 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts @@ -11,7 +11,7 @@ import { ApmMetric } from '../metrics'; import { apmAggResponseHandler, apmUuidsAgg, apmAggFilterPath } from './_apm_stats'; import { getTimeOfLastEvent } from './_get_time_of_last_event'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts index 9a59620a154ef..cdb41945bd053 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts @@ -7,7 +7,7 @@ import { BeatsMetric, BeatsMetricFields } from '../metrics'; import { createQuery } from '../create_query'; -import { getBeatDataset } from '../cluster/get_index_patterns'; +import { getBeatDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all Beats instances. diff --git a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts index f1914d0bc9f2b..8e0a6236a2fd9 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts @@ -10,7 +10,7 @@ import { createBeatsQuery } from './create_beats_query'; import { beatsAggFilterPath, beatsUuidsAgg, beatsAggResponseHandler } from './_beats_stats'; import type { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts index d4ea1363054f6..f5ea6aa19c0fe 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts @@ -10,7 +10,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from './get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; export interface FindSupportClusterRequestPayload { timeRange: TimeRange; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts index b0144c3a84391..bc25cf3280182 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts @@ -9,7 +9,7 @@ import { createQuery } from '../create_query'; import { ElasticsearchMetric } from '../metrics'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from './get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; // is this being used anywhere? not called within the app diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts index 6f082dcdb97ac..b753388af7d5d 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts @@ -41,7 +41,7 @@ import { LegacyRequest, Cluster } from '../../types'; import { RulesByType } from '../../../common/types/alerts'; import { getClusterRuleDataForClusters, getInstanceRuleDataForClusters } from '../kibana/rules'; import { Globals } from '../../static_globals'; -import { getIndexPatterns } from './get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; /** * Get all clusters or the cluster associated with {@code clusterUuid} when it is defined. @@ -123,25 +123,19 @@ export async function getClustersFromRequest( // update clusters with license check results const getSupportedClusters = flagSupportedClusters(req, CCS_REMOTE_PATTERN); clusters = await getSupportedClusters(clusters); + clusters = initializeClusters(clusters); // add alerts data if (isInCodePath(codePaths, [CODE_PATH_ALERTS])) { - const rulesClient = req.getRulesClient(); - const alertStatus = await fetchStatus( - rulesClient, - undefined, - clusters.map((cluster) => get(cluster, 'elasticsearch.cluster.id', cluster.cluster_uuid)) + const rulesClient = await req.getRulesClient(); + const clustersIds = clusters.map((cluster) => + get(cluster, 'elasticsearch.cluster.id', cluster.cluster_uuid) ); - for (const cluster of clusters) { - if (!rulesClient) { - cluster.alerts = { - list: {}, - alertsMeta: { - enabled: false, - }, - }; - } else { + if (rulesClient) { + const alertStatus = await fetchStatus(rulesClient, undefined, clustersIds); + + for (const cluster of clusters) { try { cluster.alerts = { list: Object.keys(alertStatus).reduce((acc, ruleTypeName) => { @@ -163,12 +157,6 @@ export async function getClustersFromRequest( req.logger.warn( `Unable to fetch alert status because '${err.message}'. Alerts may not properly show up in the UI.` ); - cluster.alerts = { - list: {}, - alertsMeta: { - enabled: true, - }, - }; } } } @@ -284,3 +272,13 @@ export async function getClustersFromRequest( return getClustersSummary(req.server, clusters as EnhancedClusters[], kibanaUuid, isCcrEnabled); } + +const initializeClusters = (clusters: Cluster[]): Cluster[] => { + return clusters.map((cluster) => ({ + ...cluster, + list: {}, + alertsMeta: { + enabled: false, + }, + })); +}; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts index 3415ac09dad25..4d6ca01e3e6e7 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts @@ -8,7 +8,7 @@ import { find } from 'lodash'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns } from './get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts index 240607eb8a08b..59a66b8b9ea4d 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts @@ -11,7 +11,7 @@ import { parseCrossClusterPrefix } from '../../../common/ccs_utils'; import { getClustersState } from './get_clusters_state'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from './get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/details/get_series.ts b/x-pack/plugins/monitoring/server/lib/details/get_series.ts index 3b325864d8036..854c5a67db307 100644 --- a/x-pack/plugins/monitoring/server/lib/details/get_series.ts +++ b/x-pack/plugins/monitoring/server/lib/details/get_series.ts @@ -22,7 +22,7 @@ import { DS_INDEX_PATTERN_METRICS, } from '../../../common/constants'; import { formatUTCTimestampForTimezone } from '../format_timezone'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import type { Metric } from '../metrics/metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts index 4dd568bc2f877..f809e6e358e7c 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts @@ -10,7 +10,7 @@ import { ElasticsearchMetric } from '../metrics'; import { createQuery } from '../create_query'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export async function checkCcrEnabled(req: LegacyRequest, ccs: string) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts index 81262ddb3e3f0..baaa06c1421ab 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts @@ -16,7 +16,7 @@ import { ElasticsearchResponseHit, } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts index f26d9df66201b..ab724a2c49cf1 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts @@ -11,7 +11,7 @@ import { ElasticsearchMetric } from '../metrics'; import { ML_SUPPORTED_LICENSES } from '../../../common/constants'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /* diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts index b2cffbcf36671..4da1099fd5836 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts @@ -11,7 +11,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse(shardStats: any, indexUuid: string) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts index e11971ac4f8d1..6b40c8480603d 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts @@ -13,7 +13,7 @@ import { calculateRate } from '../../calculate_rate'; import { getUnassignedShards } from '../shards'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts index e210187ab7f90..c050f5fac52b2 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts @@ -17,7 +17,7 @@ import { ElasticsearchLegacySource, } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts index 27c458a4fbd28..968e5200d7040 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts @@ -10,7 +10,10 @@ import { get } from 'lodash'; import { ElasticsearchMetric } from '../../../metrics'; import { createQuery } from '../../../create_query'; import { LegacyRequest, Bucket } from '../../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../../cluster/get_index_patterns'; +import { + getIndexPatterns, + getElasticsearchDataset, +} from '../../../../../common/get_index_patterns'; import { Globals } from '../../../../static_globals'; export async function getNodeIds( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts index 4308e60ed64a7..66004202df261 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts @@ -14,7 +14,10 @@ import { handleResponse } from './handle_response'; import { LISTING_METRICS_NAMES, LISTING_METRICS_PATHS } from './nodes_listing_metrics'; import { LegacyRequest } from '../../../../types'; import { ElasticsearchModifiedSource } from '../../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../../cluster/get_index_patterns'; +import { + getIndexPatterns, + getElasticsearchDataset, +} from '../../../../../common/get_index_patterns'; import { Globals } from '../../../../static_globals'; /* Run an aggregation on node_stats to get stat data for the selected time diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts index 2d30159a4cab1..dd346cc279591 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts @@ -11,7 +11,7 @@ import { ElasticsearchMetric } from '../../metrics'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; async function getUnassignedShardData(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts index c0dd5c29b4f2f..c5be726403745 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts @@ -10,7 +10,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; async function getShardCountPerNode(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts index b4cb77f2a6c10..0aac81e202f0b 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts @@ -9,7 +9,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse, ElasticsearchLegacySource } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse(response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts index d5af43e216834..717dc38814ae2 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts @@ -9,7 +9,7 @@ import { get } from 'lodash'; import { ElasticsearchModifiedSource, ElasticsearchResponse } from '../../../../common/types/es'; import { Globals } from '../../../static_globals'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts index 4204166b4a381..ddda97decbdd9 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts @@ -8,7 +8,7 @@ import { EnterpriseSearchMetric, EnterpriseSearchMetricFields } from '../metrics'; import { createQuery } from '../create_query'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; -import { getEntsearchDataset } from '../cluster/get_index_patterns'; +import { getEntsearchDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all Enterprise Search instances. diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts index 0011c965c8654..89af39c7b04e3 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts @@ -9,7 +9,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { EnterpriseSearchMetric } from '../metrics'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts index 526e7ec919405..63c09d388b5de 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts @@ -10,7 +10,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { entSearchAggFilterPath, diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts index 610a83d814289..4ab11001c8990 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts @@ -9,7 +9,7 @@ import { merge } from 'lodash'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { MissingRequiredError } from '../error_missing_required'; import { buildKibanaInfo } from './build_kibana_info'; import { isKibanaStatusStale } from './is_kibana_status_stale'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts index 9f45b0125b93a..4796a340aaa4c 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import { ElasticsearchResponse, ElasticsearchResponseHit } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { KibanaMetric } from '../metrics'; import { buildKibanaInfo, KibanaInfo } from './build_kibana_info'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts index f576fc4913f85..82da6c42c8f4f 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts @@ -8,7 +8,7 @@ import { chain, find } from 'lodash'; import { Globals } from '../../static_globals'; import { Bucket, Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { KibanaClusterMetric } from '../metrics'; import { isKibanaStatusStale } from './is_kibana_status_stale'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts index 5151a44ad546d..7c4ee32cde9a8 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts @@ -5,7 +5,7 @@ * 2.0. */ import { Cluster, LegacyRequest } from '../../../types'; -import { getIndexPatterns, getKibanaDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; import { createQuery } from '../../create_query'; import { KibanaClusterRuleMetric } from '../../metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts index 0e986f5f3d7fc..0de56533bf786 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts @@ -5,7 +5,7 @@ * 2.0. */ import { Cluster, LegacyRequest } from '../../../types'; -import { getIndexPatterns, getKibanaDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; import { createQuery } from '../../create_query'; import { KibanaClusterRuleMetric } from '../../metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts b/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts deleted file mode 100644 index 52b0f43647386..0000000000000 --- a/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { LogsSharedPluginSetup } from '@kbn/logs-shared-plugin/server'; -import { CCS_REMOTE_PATTERN, INFRA_SOURCE_ID } from '../../../common/constants'; -import { MonitoringConfig } from '../../config'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; - -export const initLogView = (config: MonitoringConfig, logsShared: LogsSharedPluginSetup) => { - if (logsShared) { - const logsIndexPattern = getIndexPatterns({ - config, - type: 'logs', - ccs: CCS_REMOTE_PATTERN, - }); - - logsShared.logViews.defineInternalLogView(INFRA_SOURCE_ID, { - name: 'Elastic Stack Logs', - logIndices: { - type: 'index_name', - indexName: logsIndexPattern, - }, - }); - } -}; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts index 7babdff3854b9..295f78803e678 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts @@ -10,7 +10,7 @@ import { LegacyRequest, Cluster, Bucket } from '../../types'; import { LOGSTASH } from '../../../common/constants'; import { createQuery } from '../create_query'; import { LogstashClusterMetric } from '../metrics'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; const { MEMORY, PERSISTED } = LOGSTASH.QUEUE_TYPES; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts index ca54da09dce25..347085f162e7b 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts @@ -12,7 +12,7 @@ import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; import { standaloneClusterFilter } from '../standalone_clusters/standalone_cluster_query_filter'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(resp: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts index 0d10d87d961db..a153b43fb26c3 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts @@ -11,7 +11,7 @@ import { calculateAvailability } from '../calculate_availability'; import { LogstashMetric } from '../metrics'; import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; interface Logstash { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts index 38f716cb35867..88950a207b9aa 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts @@ -11,7 +11,7 @@ import { getLogstashPipelineIds } from './get_pipeline_ids'; import { sortPipelines } from './sort_pipelines'; import { paginate } from '../pagination/paginate'; import { getMetrics } from '../details/get_metrics'; -import { getLogstashDataset } from '../cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../common/get_index_patterns'; import { LegacyRequest, Pipeline, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts index 59473977dc947..348b1c1bb61cd 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { LegacyRequest, Bucket, Pipeline } from '../../types'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; interface GetLogstashPipelineIdsParams { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts index be1612cfb4af9..01aa42e79873a 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts @@ -9,7 +9,7 @@ import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { LegacyRequest, PipelineVersion } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export async function getPipelineStateDocument({ diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts index 56785a4eee211..a76eb3b870317 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts @@ -10,7 +10,7 @@ import { PostLogstashPipelineRequestPayload, } from '../../../common/http_api/logstash'; import { LegacyRequest, PipelineVersion } from '../../types'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts index 2f464c050694a..ceddc6ec46951 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts @@ -8,7 +8,7 @@ import { get, orderBy } from 'lodash'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import { LegacyRequest, PipelineVersion } from '../../types'; import { mergePipelineVersions } from './merge_pipeline_versions'; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts index 52c738806c1ea..6b2758392ac69 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts @@ -10,7 +10,7 @@ import { PostLogstashPipelineRequestPayload, } from '../../../common/http_api/logstash'; import { LegacyRequest, PipelineVersion } from '../../types'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap index 24d9d52224fa4..242bfaeaffb6b 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap +++ b/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap @@ -5981,7 +5981,7 @@ Object { "isNotSupportedInInternalCollection": undefined, "label": "Pipeline Node Count", "legendFormat": undefined, - "mbField": undefined, + "mbField": "logstash.node.stats.logstash.uuid", "metricAgg": undefined, "periodsField": undefined, "quotaField": undefined, @@ -6437,7 +6437,7 @@ Object { "isNotSupportedInInternalCollection": undefined, "label": "Pipeline Node Count", "legendFormat": undefined, - "mbField": undefined, + "mbField": "logstash.node.stats.logstash.uuid", "metricAgg": undefined, "periodsField": undefined, "quotaField": undefined, diff --git a/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts b/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts index fd150864c6b2e..b1240a2ca9798 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts +++ b/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts @@ -7,11 +7,11 @@ /* eslint-disable max-classes-per-file */ -import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { ClusterMetric, Metric, MetricOptions } from '../classes'; -import { LARGE_FLOAT } from '../../../../common/formatting'; +import _ from 'lodash'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../../common/constants'; +import { LARGE_FLOAT } from '../../../../common/formatting'; +import { ClusterMetric, Metric, MetricOptions } from '../classes'; const msTimeUnitLabel = i18n.translate('xpack.monitoring.metrics.logstash.msTimeUnitLabel', { defaultMessage: 'ms', @@ -411,7 +411,7 @@ export class LogstashPipelineThroughputMetric extends LogstashMetric { type LogstashPipelineNodeCountMetricOptions = Pick< MetricOptions, - 'field' | 'label' | 'description' | 'format' | 'units' + 'field' | 'label' | 'mbField' | 'description' | 'format' | 'units' > & Partial>; @@ -427,15 +427,10 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { }: { pageOfPipelines: Array<{ id: string }>; }) => { - const termAggExtras: { - include: string[]; - } = { - include: [], - }; + const include: string[] | undefined = pageOfPipelines?.length + ? pageOfPipelines.map((pipeline) => pipeline.id) + : undefined; - if (pageOfPipelines) { - termAggExtras.include = pageOfPipelines.map((pipeline) => pipeline.id); - } return { pipelines_nested: { nested: { @@ -446,7 +441,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { terms: { field: 'logstash_stats.pipelines.id', size: 1000, - ...termAggExtras, + include, }, aggs: { to_root: { @@ -472,7 +467,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { terms: { field: 'logstash.node.stats.pipelines.id', size: 1000, - ...termAggExtras, + include, }, aggs: { to_root: { @@ -480,7 +475,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { aggs: { node_count: { cardinality: { - field: this.field, + field: this.mbField, }, }, }, diff --git a/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts b/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts index 97119289d2139..73aa91ef6f5fa 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts +++ b/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts @@ -6,23 +6,23 @@ */ import { i18n } from '@kbn/i18n'; +import { + LARGE_ABBREVIATED, + LARGE_BYTES, + LARGE_FLOAT, + SMALL_BYTES, +} from '../../../../common/formatting'; import { QuotaMetric } from '../classes'; import { - LogstashEventsRateClusterMetric, LogstashEventsLatencyClusterMetric, - LogstashEventsRateMetric, LogstashEventsLatencyMetric, + LogstashEventsRateClusterMetric, + LogstashEventsRateMetric, LogstashMetric, + LogstashPipelineNodeCountMetric, LogstashPipelineQueueSizeMetric, LogstashPipelineThroughputMetric, - LogstashPipelineNodeCountMetric, } from './classes'; -import { - LARGE_FLOAT, - LARGE_BYTES, - SMALL_BYTES, - LARGE_ABBREVIATED, -} from '../../../../common/formatting'; const instanceSystemLoadTitle = i18n.translate( 'xpack.monitoring.metrics.logstash.systemLoadTitle', @@ -451,6 +451,7 @@ export const metrics = { logstash_cluster_pipeline_nodes_count: new LogstashPipelineNodeCountMetric({ field: 'logstash_stats.logstash.uuid', label: pipelineNodeCountLabel, + mbField: 'logstash.node.stats.logstash.uuid', description: pipelineNodeCountDescription, format: LARGE_FLOAT, units: '', @@ -459,6 +460,7 @@ export const metrics = { uuidField: 'logstash_stats.logstash.uuid', // TODO: add comment explaining why field: 'logstash_stats.logstash.uuid', label: pipelineNodeCountLabel, + mbField: 'logstash.node.stats.logstash.uuid', description: pipelineNodeCountDescription, format: LARGE_FLOAT, units: '', diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts index e7ffe701fbd1a..ce03cc5aecf3b 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts @@ -7,7 +7,6 @@ import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { infraPluginMock } from '@kbn/infra-plugin/server/mocks'; -import { logsSharedPluginMock } from '@kbn/logs-shared-plugin/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; import { configSchema, createConfig } from '../../../config'; @@ -39,7 +38,6 @@ const mockReq = ( usageCollection: usageCollectionSetup, features: featuresPluginMock.createSetup(), infra: infraPluginMock.createSetupContract(), - logsShared: logsSharedPluginMock.createSetupContract(), }, }, }, @@ -96,7 +94,7 @@ const mockReq = ( headers: {}, getKibanaStatsCollector: () => null, getUiSettingsService: () => null, - getActionTypeRegistry: () => null, + getActionTypeRegistry: () => [], getRulesClient: () => null, getActionsClient: () => null, }; diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts index 6d800e83c2d7c..41313bfb347a2 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts @@ -14,7 +14,7 @@ import { } from '../../../../common/constants'; import { TimeRange } from '../../../../common/http_api/shared'; import { LegacyRequest } from '../../../types'; -import { getLegacyIndexPattern } from '../../cluster/get_index_patterns'; +import { getLegacyIndexPattern } from '../../../../common/get_index_patterns'; import { getLivesNodes } from '../../elasticsearch/nodes/get_nodes/get_live_nodes'; interface Bucket { diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts index 042340eb0669c..d9ec794dd7606 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts @@ -14,7 +14,7 @@ import { getIndexPatterns, getLogstashDataset, getBeatDataset, -} from '../cluster/get_index_patterns'; +} from '../../../common/get_index_patterns'; export async function hasStandaloneClusters(req: LegacyRequest, ccs: string) { const lsIndexPatterns = getIndexPatterns({ diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 72063805b3383..dbf375aa2e057 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -23,7 +23,9 @@ import { import { get } from 'lodash'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { RouteMethod } from '@kbn/core/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { KIBANA_MONITORING_LOGGING_TAG, KIBANA_STATS_TYPE_MONITORING, @@ -36,7 +38,6 @@ import { configSchema, createConfig, MonitoringConfig } from './config'; import { instantiateClient } from './es_client/instantiate_client'; import { initBulkUploader } from './kibana_monitoring'; import { registerCollectors } from './kibana_monitoring/collectors'; -import { initLogView } from './lib/logs/init_log_view'; import { LicenseService } from './license_service'; import { requireUIRoutes } from './routes'; import { EndpointTypes, Globals } from './static_globals'; @@ -203,7 +204,6 @@ export class MonitoringPlugin alerting: plugins.alerting, logger: this.log, }); - initLogView(config, plugins.logsShared); } } @@ -267,6 +267,11 @@ export class MonitoringPlugin } registerPluginInUI(plugins: PluginsSetup) { + const alertingFeatures = RULES.map((ruleTypeId) => ({ + ruleTypeId, + consumers: ['monitoring', ALERTING_FEATURE_ID, AlertConsumers.OBSERVABILITY], + })); + plugins.features.registerKibanaFeature({ id: 'monitoring', name: i18n.translate('xpack.monitoring.featureRegistry.monitoringFeatureName', { @@ -277,7 +282,7 @@ export class MonitoringPlugin app: ['monitoring', 'kibana'], catalogue: ['monitoring'], privileges: null, - alerting: RULES, + alerting: alertingFeatures, reserved: { description: i18n.translate('xpack.monitoring.feature.reserved.description', { defaultMessage: 'To grant users access, you should also assign the monitoring_user role.', @@ -294,10 +299,10 @@ export class MonitoringPlugin }, alerting: { rule: { - all: RULES, + all: alertingFeatures, }, alert: { - all: RULES, + all: alertingFeatures, }, }, ui: [], @@ -337,7 +342,7 @@ export class MonitoringPlugin payload: req.body, getKibanaStatsCollector: () => this.legacyShimDependencies.kibanaStatsCollector, getUiSettingsService: () => coreContext.uiSettings.client, - getActionTypeRegistry: () => actionContext?.listTypes(), + getActionTypeRegistry: () => actionContext?.listTypes() ?? [], getRulesClient: () => { try { return plugins.alerting.getRulesClientWithRequest(req); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts b/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts index 5ed5b85168ee2..7b0c07fef8df3 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts @@ -8,7 +8,7 @@ import type { LegacyRequest, MonitoringCore } from '../../../../types'; import type { MonitoringConfig } from '../../../../config'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getIndexPatterns, getDsIndexPattern } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns, getDsIndexPattern } from '../../../../../common/get_index_patterns'; import { getHealthRequestQueryRT } from '../../../../../common/http_api/_health'; import type { TimeRange } from '../../../../../common/http_api/shared'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts index dac9d6b59ca1a..0935b76e7fba9 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts @@ -12,7 +12,7 @@ import { getKibanaDataset, getLogstashDataset, getEntsearchDataset, -} from '../../../../../lib/cluster/get_index_patterns'; +} from '../../../../../../common/get_index_patterns'; const MAX_BUCKET_SIZE = 100; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index 8b919fd1f86ea..593f3c9b2b4ab 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -30,6 +30,7 @@ export function enableAlertsRoute(server: MonitoringCore, npRoute: RouteDependen const actionContext = await context.actions; const alerts = RulesFactory.getAll(); + if (alerts.length) { const { isSufficientlySecure, hasPermanentEncryptionKey } = npRoute.alerting ?.getSecurityHealth @@ -49,9 +50,10 @@ export function enableAlertsRoute(server: MonitoringCore, npRoute: RouteDependen } } - const rulesClient = alertingContext?.getRulesClient(); + const rulesClient = await alertingContext?.getRulesClient(); const actionsClient = actionContext?.getActionsClient(); const types = actionContext?.listTypes(); + if (!rulesClient || !actionsClient || !types) { return response.ok({ body: undefined }); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts index 64a0b7b92d85f..a6c7d9b833ee1 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts @@ -36,7 +36,7 @@ export function alertStatusRoute(npRoute: RouteDependencies) { try { const { clusterUuid } = request.params; const { alertTypeIds, filters } = request.body; - const rulesClient = (await context.alerting)?.getRulesClient(); + const rulesClient = await (await context.alerting)?.getRulesClient(); if (!rulesClient) { return response.ok({ body: undefined }); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts index 8c8d7e0ad2c69..3e4d903ec8af2 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts @@ -14,7 +14,7 @@ import { getApmInfo } from '../../../../lib/apm'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_instance'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts index bb8086867ed05..1b19d49007794 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts @@ -13,7 +13,7 @@ import { import { getApms, getStats } from '../../../../lib/apm'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; export function apmInstancesRoute(server: MonitoringCore) { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts index 30ef661feb0f4..a248df56f9e2a 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts @@ -14,7 +14,7 @@ import { getBeatSummary } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_detail'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts index b59cec2898617..96433d756e8ae 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts @@ -13,7 +13,7 @@ import { import { getBeats, getStats } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; export function beatsListingRoute(server: MonitoringCore) { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts index cbdc28ebf4f9b..6c79a56a57412 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts @@ -14,7 +14,7 @@ import { getLatestStats, getStats } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_overview'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts index 7c939407ef156..03f9fff6bc943 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts @@ -9,7 +9,7 @@ import { get, groupBy } from 'lodash'; import { getIndexPatterns, getElasticsearchDataset, -} from '../../../../lib/cluster/get_index_patterns'; +} from '../../../../../common/get_index_patterns'; import { postElasticsearchCcrRequestParamsRT, postElasticsearchCcrRequestPayloadRT, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts index 3e215aaf67e35..b02ba1e455bce 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts @@ -15,7 +15,7 @@ import { ElasticsearchResponse } from '../../../../../common/types/es'; import { getIndexPatterns, getElasticsearchDataset, -} from '../../../../lib/cluster/get_index_patterns'; +} from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts index 9aed104920e83..e96fb9dbad629 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts @@ -13,7 +13,7 @@ import { postElasticsearchIndexDetailResponsePayloadRT, } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getIndexSummary } from '../../../../lib/elasticsearch/indices'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts index 763f8005abc93..05406a2d001e6 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts @@ -14,7 +14,7 @@ import { postElasticsearchNodeDetailResponsePayloadRT, } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts index 0b97f9ea63363..269a924648a61 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts @@ -13,7 +13,7 @@ import { } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getLastRecovery } from '../../../../lib/elasticsearch/get_last_recovery'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts index f398a1bda59d7..135fa58e3d28b 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts @@ -16,7 +16,7 @@ import { } from '../../../../../common/http_api/kibana'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { MonitoringCore } from '../../../../types'; -import { getKibanaDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getKibanaDataset } from '../../../../../common/get_index_patterns'; export function kibanaOverviewRoute(server: MonitoringCore) { const validateParams = createValidationFunction(postKibanaOverviewRequestParamsRT); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts index 5c7bbc36b168c..e6b2034ca22cd 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts @@ -19,7 +19,7 @@ import { import { metricSets } from './metric_set_node'; import { MonitoringCore } from '../../../../types'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getLogstashDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../../../common/get_index_patterns'; const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts index 26d63693fd6dd..15661a130055d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts @@ -15,7 +15,7 @@ import { handleError } from '../../../../lib/errors'; import { metricSet } from './metric_set_overview'; import { MonitoringCore } from '../../../../types'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getLogstashDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../../../common/get_index_patterns'; export function logstashOverviewRoute(server: MonitoringCore) { const validateParams = createValidationFunction(postLogstashOverviewRequestParamsRT); diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 06c796764b5f7..14ef949b93949 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -24,18 +24,14 @@ import type { } from '@kbn/actions-plugin/server'; import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server'; import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server'; -import { - PluginStartContract as AlertingPluginStartContract, - PluginSetupContract as AlertingPluginSetupContract, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { InfraPluginSetup, InfraRequestHandlerContext } from '@kbn/infra-plugin/server'; -import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; import { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { RouteConfig, RouteMethod, Headers } from '@kbn/core/server'; -import { LogsSharedPluginSetup } from '@kbn/logs-shared-plugin/server'; +import { ActionTypeRegistry } from '@kbn/actions-plugin/server/action_type_registry'; import { ElasticsearchModifiedSource } from '../common/types/es'; import { RulesByType } from '../common/types/alerts'; import { configSchema, MonitoringConfig } from './config'; @@ -54,10 +50,9 @@ export interface PluginsSetup { encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; usageCollection?: UsageCollectionSetup; features: FeaturesPluginSetup; - alerting?: AlertingPluginSetupContract; + alerting?: AlertingServerSetup; infra: InfraPluginSetup; cloud?: CloudSetup; - logsShared: LogsSharedPluginSetup; } export type RequestHandlerContextMonitoringPlugin = CustomRequestHandlerContext<{ @@ -68,7 +63,7 @@ export type RequestHandlerContextMonitoringPlugin = CustomRequestHandlerContext< }>; export interface PluginsStart { - alerting: AlertingPluginStartContract; + alerting: AlertingServerStart; actions: ActionsPluginsStartContact; licensing: LicensingPluginStart; } @@ -78,7 +73,7 @@ export interface RouteDependencies { router: IRouter; licenseService: MonitoringLicenseService; encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; - alerting?: AlertingPluginSetup; + alerting?: AlertingServerSetup; logger: Logger; } @@ -129,9 +124,11 @@ export interface LegacyRequest { headers: Headers; getKibanaStatsCollector: () => any; getUiSettingsService: () => any; - getActionTypeRegistry: () => any; - getRulesClient: () => any; - getActionsClient: () => any; + getActionTypeRegistry: () => ReturnType; + getRulesClient: () => ReturnType | null; + getActionsClient: () => ReturnType< + ActionsPluginsStartContact['getActionsClientWithRequest'] + > | null; server: LegacyServer; } diff --git a/x-pack/plugins/monitoring/tsconfig.json b/x-pack/plugins/monitoring/tsconfig.json index 48b538a00c1eb..6be14087cc11d 100644 --- a/x-pack/plugins/monitoring/tsconfig.json +++ b/x-pack/plugins/monitoring/tsconfig.json @@ -40,7 +40,6 @@ "@kbn/shared-ux-router", "@kbn/observability-shared-plugin", "@kbn/shared-ux-link-redirect-app", - "@kbn/logs-shared-plugin", "@kbn/alerts-as-data-utils", "@kbn/rule-data-utils", "@kbn/react-kibana-mount", diff --git a/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.ts b/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.ts new file mode 100644 index 0000000000000..784ab0b534256 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.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 { + AlertConsumers, + OBSERVABILITY_RULE_TYPE_IDS, + type ValidFeatureId, +} from '@kbn/rule-data-utils'; + +export const apmAlertingConsumers: ValidFeatureId[] = [ + AlertConsumers.LOGS, + AlertConsumers.APM, + AlertConsumers.SLO, + AlertConsumers.OBSERVABILITY, + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.ALERTS, +]; + +export const apmAlertingRuleTypeIds: string[] = [...OBSERVABILITY_RULE_TYPE_IDS]; diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts index af23fc8a2ad7e..0ef8fb40ceb38 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts @@ -15,8 +15,7 @@ const timeRange = { rangeFrom: start, rangeTo: end, }; -// flaky -describe.skip('Transaction details', () => { +describe('Transaction details', () => { before(() => { synthtrace.index( opbeans({ @@ -34,7 +33,7 @@ describe.skip('Transaction details', () => { cy.loginAsViewerUser(); }); - it('shows transaction name and transaction charts', () => { + it('shows transaction name and transaction charts', { defaultCommandTimeout: 60000 }, () => { cy.intercept('GET', '/internal/apm/services/opbeans-java/transactions/charts/latency?*').as( 'transactionLatencyRequest' ); @@ -60,7 +59,7 @@ describe.skip('Transaction details', () => { '@transactionThroughputRequest', '@transactionFailureRateRequest', ], - { timeout: 30000 } + { timeout: 60000 } ).spread((latencyInterception, throughputInterception, failureRateInterception) => { expect(latencyInterception.request.query.transactionName).to.be.eql('GET /api/product'); @@ -106,7 +105,9 @@ describe.skip('Transaction details', () => { ); cy.contains('Create SLO'); }); - it('shows top errors table', () => { + + // flaky + it.skip('shows top errors table', () => { cy.visitKibana( `/app/apm/services/opbeans-java/transactions/view?${new URLSearchParams({ ...timeRange, diff --git a/x-pack/plugins/observability_solution/apm/kibana.jsonc b/x-pack/plugins/observability_solution/apm/kibana.jsonc index 656f898f24064..bcb0801fc6394 100644 --- a/x-pack/plugins/observability_solution/apm/kibana.jsonc +++ b/x-pack/plugins/observability_solution/apm/kibana.jsonc @@ -37,7 +37,8 @@ "lens", "maps", "uiActions", - "logsDataAccess" + "logsDataAccess", + "savedSearch", ], "optionalPlugins": [ "actions", diff --git a/x-pack/plugins/observability_solution/apm/public/application/index.tsx b/x-pack/plugins/observability_solution/apm/public/application/index.tsx index 23dde7de81469..f9785a136b06e 100644 --- a/x-pack/plugins/observability_solution/apm/public/application/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/application/index.tsx @@ -59,6 +59,7 @@ export const renderApp = ({ observabilityAIAssistant: pluginsStart.observabilityAIAssistant, share: pluginsSetup.share, kibanaEnvironment, + licensing: pluginsStart.licensing, }; // render APM feedback link in global help menu diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx index a5d0df3b05538..682634819e623 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx @@ -13,6 +13,10 @@ import { EuiPanel, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { BoolQuery } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { + apmAlertingConsumers, + apmAlertingRuleTypeIds, +} from '../../../../common/alerting/config/apm_alerting_feature_ids'; import { ApmPluginStartDeps } from '../../../plugin'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { SERVICE_NAME } from '../../../../common/es_fields/apm'; @@ -107,7 +111,8 @@ export function AlertsOverview() { alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} id={'service-overview-alerts'} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={[AlertConsumers.APM, AlertConsumers.OBSERVABILITY]} + ruleTypeIds={apmAlertingRuleTypeIds} + consumers={apmAlertingConsumers} query={esQuery} showAlertStatusWithFlapping cellContext={{ observabilityRuleTypeRegistry }} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index a1dadbf186b91..35f502642518f 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -6,9 +6,9 @@ */ import React, { useMemo } from 'react'; -import moment from 'moment'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { LogStream } from '@kbn/logs-shared-plugin/public'; +import { LazySavedSearchComponent } from '@kbn/saved-search-component'; +import useAsync from 'react-use/lib/useAsync'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; @@ -35,6 +35,19 @@ export function ServiceLogs() { } export function ClassicServiceLogsStream() { + const { + services: { + logsDataAccess: { + services: { logSourcesService }, + }, + embeddable, + dataViews, + data: { + search: { searchSource }, + }, + }, + } = useKibana(); + const { serviceName } = useApmServiceContext(); const { @@ -62,17 +75,31 @@ export function ClassicServiceLogsStream() { [environment, kuery, serviceName, start, end] ); - return ( - ({ from: start, to: end }), [start, end]); + + const query = useMemo( + () => ({ + language: 'kuery', + query: getInfrastructureKQLFilter({ data, serviceName, environment }), + }), + [data, serviceName, environment] + ); + + return logSources.value ? ( + - ); + ) : null; } export function ServiceLogsOverview() { diff --git a/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx index e8ab9530b574e..03711b7265e3f 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx +++ b/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx @@ -19,6 +19,7 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { ApmPluginSetupDeps } from '../../plugin'; import type { ConfigSchema } from '../..'; import type { KibanaEnvContext } from '../kibana_environment_context/kibana_environment_context'; @@ -40,6 +41,7 @@ export interface ApmPluginContextValue { share: SharePluginSetup; kibanaEnvironment: KibanaEnvContext; lens: LensPublicStart; + licensing: LicensingPluginStart; } export const ApmPluginContext = createContext({} as ApmPluginContextValue); diff --git a/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx index 569c21637ceff..927e4367dd376 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx +++ b/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx @@ -14,8 +14,7 @@ import { InvalidLicenseNotification } from './invalid_license_notification'; export const LicenseContext = React.createContext(undefined); export function LicenseProvider({ children }: { children: React.ReactChild }) { - const { plugins } = useApmPluginContext(); - const { licensing } = plugins; + const { licensing } = useApmPluginContext(); const license = useObservable(licensing.license$); // if license is not loaded yet, consider it valid const hasInvalidLicense = license?.isActive === false; diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts index ab8b82899551b..532c0498f7a56 100644 --- a/x-pack/plugins/observability_solution/apm/public/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts @@ -34,7 +34,7 @@ import { Start as InspectorPluginStart } from '@kbn/inspector-plugin/public'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/public'; -import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { MapsStartApi } from '@kbn/maps-plugin/public'; import type { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/public'; import type { @@ -70,6 +70,8 @@ import { map } from 'rxjs'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public'; +import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { ConfigSchema } from '.'; import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types'; import { registerEmbeddables } from './embeddable/register_embeddables'; @@ -96,7 +98,6 @@ export interface ApmPluginSetupDeps { unifiedSearch: UnifiedSearchPublicPluginStart; features: FeaturesPluginSetup; home?: HomePublicPluginSetup; - licensing: LicensingPluginSetup; licenseManagement?: LicenseManagementUIPluginSetup; ml?: MlPluginSetup; observability: ObservabilityPublicSetup; @@ -122,7 +123,7 @@ export interface ApmPluginStartDeps { embeddable: EmbeddableStart; home: void; inspector: InspectorPluginStart; - licensing: void; + licensing: LicensingPluginStart; maps?: MapsStartApi; ml?: MlPluginStart; triggersActionsUi: TriggersAndActionsUIPublicPluginStart; @@ -144,6 +145,8 @@ export interface ApmPluginStartDeps { metricsDataAccess: MetricsDataPluginStart; uiSettings: IUiSettingsClient; logsShared: LogsSharedClientStartExports; + logsDataAccess: LogsDataAccessPluginStart; + savedSearch: SavedSearchPublicPluginStart; } const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', { @@ -198,7 +201,6 @@ export class ApmPlugin implements Plugin { const { featureFlags } = config; if (pluginSetupDeps.home) { - pluginSetupDeps.home.environment.update({ apmUi: true }); pluginSetupDeps.home.featureCatalogue.register(featureCatalogueEntry); } diff --git a/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts b/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts index 1dff57cef6602..6a65e6126ff22 100644 --- a/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts @@ -72,7 +72,10 @@ export function registerAssistantFunctions({ ruleDataClient, plugins, getApmIndices: async () => { - const apmIndices = await plugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await resources.context.core; + const apmIndices = await plugins.apmDataAccess.setup.getApmIndices( + coreContext.savedObjects.client + ); return apmIndices; }, }; diff --git a/x-pack/plugins/observability_solution/apm/server/feature.ts b/x-pack/plugins/observability_solution/apm/server/feature.ts index f9b047c602cda..6e129d298e0a7 100644 --- a/x-pack/plugins/observability_solution/apm/server/feature.ts +++ b/x-pack/plugins/observability_solution/apm/server/feature.ts @@ -15,10 +15,14 @@ import { import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE } from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; import { ApmRuleType } from '@kbn/rule-data-utils'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureConfig, KibanaFeatureScope } from '@kbn/features-plugin/common'; import { APM_SERVER_FEATURE_ID } from '../common/rules/apm_rule_types'; -const ruleTypes = Object.values(ApmRuleType); +const alertingFeatures = Object.values(ApmRuleType).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [APM_SERVER_FEATURE_ID, ALERTING_FEATURE_ID], +})); export const APM_FEATURE: KibanaFeatureConfig = { id: APM_SERVER_FEATURE_ID, @@ -33,7 +37,7 @@ export const APM_FEATURE: KibanaFeatureConfig = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: ruleTypes, + alerting: alertingFeatures, // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { @@ -46,10 +50,10 @@ export const APM_FEATURE: KibanaFeatureConfig = { }, alerting: { alert: { - all: ruleTypes, + all: alertingFeatures, }, rule: { - all: ruleTypes, + all: alertingFeatures, }, }, management: { @@ -67,10 +71,10 @@ export const APM_FEATURE: KibanaFeatureConfig = { }, alerting: { alert: { - read: ruleTypes, + read: alertingFeatures, }, rule: { - read: ruleTypes, + read: alertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts b/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts index b0e601fd4c0db..95c29472dbc79 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts @@ -12,6 +12,7 @@ import { DataTier } from '@kbn/observability-shared-plugin/common'; import { searchExcludedDataTiers } from '@kbn/observability-plugin/common/ui_settings_keys'; import { estypes } from '@elastic/elasticsearch'; import { getDataTierFilterCombined } from '@kbn/apm-data-access-plugin/server/utils'; +import { apmAlertingRuleTypeIds } from '../../../common/alerting/config/apm_alerting_feature_ids'; import type { MinimalAPMRouteHandlerResources } from '../../routes/apm_routes/register_apm_server_routes'; export type ApmAlertsClient = Awaited>; @@ -31,7 +32,7 @@ export async function getApmAlertsClient({ const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const apmAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(['apm']); + const apmAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(apmAlertingRuleTypeIds); if (!apmAlertsIndices || isEmpty(apmAlertsIndices)) { throw Error('No alert indices exist for "apm"'); diff --git a/x-pack/plugins/observability_solution/apm/server/plugin.ts b/x-pack/plugins/observability_solution/apm/server/plugin.ts index de49ebcebf8b0..1142a5c69a51f 100644 --- a/x-pack/plugins/observability_solution/apm/server/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/server/plugin.ts @@ -16,6 +16,7 @@ import { registerAssistantFunctions } from './assistant_functions'; import { registerDeprecations } from './deprecations'; import { APM_FEATURE, registerFeaturesUsage } from './feature'; import { createApmTelemetry } from './lib/apm_telemetry'; +import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_objects_client'; import { APM_RULE_TYPE_ALERT_CONTEXT, apmRuleTypeAlertFieldMap, @@ -114,6 +115,13 @@ export class APMPlugin }; }) as APMRouteHandlerResources['plugins']; + const apmIndicesPromise = (async () => { + const coreStart = await getCoreStart(); + const soClient = await getInternalSavedObjectsClient(coreStart); + const { getApmIndices } = plugins.apmDataAccess; + return getApmIndices(soClient); + })(); + // This if else block will go away in favour of removing Home Tutorial Integration // Ideally we will directly register a custom integration and pass the configs // for cloud, onPrem and Serverless so that the actual component can take @@ -121,8 +129,7 @@ export class APMPlugin if (currentConfig.serverlessOnboarding && plugins.customIntegrations) { plugins.customIntegrations?.registerCustomIntegration(apmTutorialCustomIntegration); } else { - plugins.apmDataAccess - .getApmIndices() + apmIndicesPromise .then((apmIndices) => { plugins.home?.tutorials.registerTutorial( tutorialProvider({ diff --git a/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts b/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts index 4c57ef4a10e1d..ea653b47145a2 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts @@ -8,10 +8,7 @@ import type { AlertsLocatorParams } from '@kbn/observability-plugin/common'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { IBasePath, Logger, SavedObjectsClientContract } from '@kbn/core/server'; -import { - PluginSetupContract as AlertingPluginSetupContract, - type IRuleTypeAlerts, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, IRuleTypeAlerts } from '@kbn/alerting-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; @@ -100,7 +97,7 @@ export const ApmRuleTypeAlertDefinition: IRuleTypeAlerts }; export interface RegisterRuleDependencies { - alerting: AlertingPluginSetupContract; + alerting: AlertingServerSetup; basePath: IBasePath; getApmIndices: (soClient: SavedObjectsClientContract) => Promise; apmConfig: APMConfig; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts index ce3e67baea1d6..9230ca4983698 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts @@ -9,7 +9,7 @@ import { IBasePath, Logger } from '@kbn/core/server'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; -import { PluginSetupContract as AlertingPluginSetupContract } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; import { APMConfig, APM_SERVER_FEATURE_ID } from '../../..'; @@ -28,7 +28,7 @@ export const createRuleTypeMocks = () => { registerType: ({ executor }) => { alertExecutor = executor; }, - } as AlertingPluginSetupContract; + } as AlertingServerSetup; const scheduleActions = jest.fn(); const getUuid = jest.fn(); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts index 59c9cdac2df83..197b4259d3f09 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts @@ -115,7 +115,10 @@ export function registerRoutes({ ); const getApmIndices = async () => { - const apmIndices = await plugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await context.core; + const apmIndices = await plugins.apmDataAccess.setup.getApmIndices( + coreContext.savedObjects.client + ); return apmIndices; }; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts index f28e3f9df8570..84e51675233c9 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts @@ -38,7 +38,8 @@ export const getAlertDetailsContextHandler = ( return async (requestContext, query) => { const resources = { getApmIndices: async () => { - return resourcePlugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await requestContext.core; + return resourcePlugins.apmDataAccess.setup.getApmIndices(coreContext.savedObjects.client); }, request: requestContext.request, params: { query: { _inspect: false } }, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts b/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts index 9d00c50b4ab48..2237548f2d325 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Logger, CoreStart } from '@kbn/core/server'; +import { Logger, CoreStart, SavedObjectsClientContract } from '@kbn/core/server'; import { FleetStartContract, PostPackagePolicyCreateCallback, @@ -22,6 +22,7 @@ import { SOURCE_MAP_API_KEY_PATH, } from './get_package_policy_decorators'; import { createInternalESClient } from '../../lib/helpers/create_es_client/create_internal_es_client'; +import { getInternalSavedObjectsClient } from '../../lib/helpers/get_internal_saved_objects_client'; import { APMRouteHandlerResources } from '../apm_routes/register_apm_server_routes'; export async function registerFleetPolicyCallbacks({ @@ -148,7 +149,7 @@ function onPackagePolicyCreateOrUpdate({ coreStart, }: { fleetPluginStart: FleetStartContract; - getApmIndices: () => Promise; + getApmIndices: (soClient: SavedObjectsClientContract) => Promise; coreStart: CoreStart; }): PutPackagePolicyUpdateCallback & PostPackagePolicyCreateCallback { return async (packagePolicy) => { @@ -157,7 +158,8 @@ function onPackagePolicyCreateOrUpdate({ } const { asInternalUser } = coreStart.elasticsearch.client; - const apmIndices = await getApmIndices(); + const savedObjectsClient = await getInternalSavedObjectsClient(coreStart); + const apmIndices = await getApmIndices(savedObjectsClient); const internalESClient = await createInternalESClient({ debug: false, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/typings.ts b/x-pack/plugins/observability_solution/apm/server/routes/typings.ts index 126ae48937648..de5aeb6031d1c 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/typings.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/typings.ts @@ -16,14 +16,12 @@ import type { import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server'; import type { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; -import type { RulesClientApi } from '@kbn/alerting-plugin/server/types'; +import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; export type ApmPluginRequestHandlerContext = CustomRequestHandlerContext<{ licensing: Pick; alerting: { - // Pick is a superset of this - // and incompatible with the start contract from the alerting plugin - getRulesClient: () => RulesClientApi; + getRulesClient: () => Promise; }; rac: Pick; }>; diff --git a/x-pack/plugins/observability_solution/apm/server/types.ts b/x-pack/plugins/observability_solution/apm/server/types.ts index 84e0d5462c43b..e99860b9d441f 100644 --- a/x-pack/plugins/observability_solution/apm/server/types.ts +++ b/x-pack/plugins/observability_solution/apm/server/types.ts @@ -24,7 +24,7 @@ import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server' import { HomeServerPluginSetup, HomeServerPluginStart } from '@kbn/home-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { ActionsPlugin } from '@kbn/actions-plugin/server'; -import { AlertingPlugin } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; @@ -78,7 +78,7 @@ export interface APMPluginSetupDependencies { observabilityAIAssistant?: ObservabilityAIAssistantServerSetup; // optional dependencies actions?: ActionsPlugin['setup']; - alerting?: AlertingPlugin['setup']; + alerting?: AlertingServerSetup; cloud?: CloudSetup; fleet?: FleetPluginSetup; home?: HomeServerPluginSetup; @@ -105,7 +105,7 @@ export interface APMPluginStartDependencies { observabilityAIAssistant?: ObservabilityAIAssistantServerStart; // optional dependencies actions?: ActionsPlugin['start']; - alerting?: AlertingPlugin['start']; + alerting?: AlertingServerStart; cloud?: undefined; fleet?: FleetPluginStart; home?: HomeServerPluginStart; diff --git a/x-pack/plugins/observability_solution/apm/tsconfig.json b/x-pack/plugins/observability_solution/apm/tsconfig.json index d3de1633dcad7..b2fda13c3f76f 100644 --- a/x-pack/plugins/observability_solution/apm/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm/tsconfig.json @@ -127,6 +127,8 @@ "@kbn/router-utils", "@kbn/react-hooks", "@kbn/alerting-comparators", + "@kbn/saved-search-component", + "@kbn/saved-search-plugin", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc index 9d80dcd71ce93..4eb0859691ba1 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc @@ -1,10 +1,7 @@ { "type": "plugin", "id": "@kbn/apm-data-access-plugin", - "owner": [ - "@elastic/obs-knowledge-team", - "@elastic/obs-ux-infra_services-team" - ], + "owner": ["@elastic/obs-ux-infra_services-team"], "group": "observability", "visibility": "private", "plugin": { @@ -18,7 +15,9 @@ "requiredPlugins": [ "data" ], - "optionalPlugins": [], + "optionalPlugins": [ + "security" + ], "requiredBundles": [] } } \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/index.ts b/x-pack/plugins/observability_solution/apm_data_access/server/index.ts index 7afaa656591c4..6b6385ded4ce4 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/index.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/index.ts @@ -91,6 +91,7 @@ export type { APMEventESSearchRequest, APMLogEventESSearchRequest, DocumentSourcesRequest, + ApmDataAccessPrivilegesCheck, HostNamesRequest, GetDocumentTypeParams, } from './types'; diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts new file mode 100644 index 0000000000000..6b8e734a10b4e --- /dev/null +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.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 { KibanaRequest } from '@kbn/core-http-server'; +import { SecurityPluginStart } from '@kbn/security-plugin-types-server'; +import { mapValues } from 'lodash'; +import { APMIndices } from '..'; + +export interface ApmDataAccessPrivilegesCheck { + request: KibanaRequest; + security?: SecurityPluginStart; + getApmIndices: () => Promise; +} + +export async function checkPrivileges({ + request, + getApmIndices, + security, +}: ApmDataAccessPrivilegesCheck) { + const authorization = security?.authz; + if (!authorization) { + return true; + } + + const [apmIndices, checkPrivilegesFn] = await Promise.all([ + getApmIndices(), + authorization.checkPrivilegesDynamicallyWithRequest(request), + ]); + + const { hasAllRequested } = await checkPrivilegesFn({ + elasticsearch: { + cluster: [], + index: mapValues(apmIndices, () => ['read']), + }, + }); + + return hasAllRequested; +} diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts index c1f8d5e3fce1f..83171dea7f444 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/tier_filter.ts @@ -13,10 +13,10 @@ export function getDataTierFilterCombined({ excludedDataTiers, }: { filter?: QueryDslQueryContainer; - excludedDataTiers: DataTier[]; + excludedDataTiers?: DataTier[]; }): QueryDslQueryContainer | undefined { if (!filter) { - return excludedDataTiers.length > 0 ? excludeTiersQuery(excludedDataTiers)[0] : undefined; + return excludedDataTiers?.length ? excludeTiersQuery(excludedDataTiers)[0] : undefined; } return !excludedDataTiers diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts b/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts index 6bf684985583a..680079d080c82 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts @@ -5,19 +5,32 @@ * 2.0. */ -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + SavedObjectsClientContract, + Logger, +} from '@kbn/core/server'; import { APMDataAccessConfig } from '.'; -import { ApmDataAccessPluginSetup, ApmDataAccessPluginStart } from './types'; +import { + ApmDataAccessPluginSetup, + ApmDataAccessPluginStart, + ApmDataAccessServerDependencies, +} from './types'; import { migrateLegacyAPMIndicesToSpaceAware } from './saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware'; import { apmIndicesSavedObjectDefinition, getApmIndicesSavedObject, } from './saved_objects/apm_indices'; import { getServices } from './services/get_services'; +import { ApmDataAccessPrivilegesCheck, checkPrivileges } from './lib/check_privileges'; export class ApmDataAccessPlugin implements Plugin { + public server?: ApmDataAccessServerDependencies; public config: APMDataAccessConfig; public logger: Logger; @@ -26,34 +39,45 @@ export class ApmDataAccessPlugin this.logger = initContext.logger.get(); } + getApmIndices = async (savedObjectsClient: SavedObjectsClientContract) => { + const apmIndicesFromSavedObject = await getApmIndicesSavedObject(savedObjectsClient); + return { ...this.config.indices, ...apmIndicesFromSavedObject }; + }; + public setup(core: CoreSetup): ApmDataAccessPluginSetup { // register saved object core.savedObjects.registerType(apmIndicesSavedObjectDefinition); - const getApmIndices = async () => { - const [coreStart] = await core.getStartServices(); - const soClient = await coreStart.savedObjects.createInternalRepository(); - - const apmIndicesFromSavedObject = await getApmIndicesSavedObject(soClient); - return { ...this.config.indices, ...apmIndicesFromSavedObject }; - }; - // expose return { apmIndicesFromConfigFile: this.config.indices, - getApmIndices, + getApmIndices: this.getApmIndices, getServices, }; } - public start(core: CoreStart) { + public start(core: CoreStart, plugins: ApmDataAccessServerDependencies) { // TODO: remove in 9.0 migrateLegacyAPMIndicesToSpaceAware({ coreStart: core, logger: this.logger }).catch((e) => { this.logger.error('Failed to run migration making APM indices space aware'); this.logger.error(e); }); - return {}; + const getApmIndicesWithInternalUserFn = async () => { + const soClient = core.savedObjects.createInternalRepository(); + return this.getApmIndices(soClient); + }; + + const startServices = { + hasPrivileges: ({ request }: Pick) => + checkPrivileges({ + request, + getApmIndices: getApmIndicesWithInternalUserFn, + security: plugins.security, + }), + }; + + return { ...startServices }; } public stop() {} diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/types.ts b/x-pack/plugins/observability_solution/apm_data_access/server/types.ts index 968590e780ee8..f10c23c1fd994 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/types.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/types.ts @@ -5,17 +5,28 @@ * 2.0. */ +import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { SecurityPluginStart } from '@kbn/security-plugin-types-server'; import type { APMIndices } from '.'; import { getServices } from './services/get_services'; +import type { ApmDataAccessPrivilegesCheck } from './lib/check_privileges'; export interface ApmDataAccessPluginSetup { apmIndicesFromConfigFile: APMIndices; - getApmIndices: () => Promise; + getApmIndices: (soClient: SavedObjectsClientContract) => Promise; getServices: typeof getServices; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ApmDataAccessPluginStart {} +export interface ApmDataAccessServerDependencies { + security?: SecurityPluginStart; +} + +export interface ApmDataAccessPluginStart { + hasPrivileges: (params: Pick) => Promise; +} +export interface ApmDataAccessServerDependencies { + security?: SecurityPluginStart; +} export type ApmDataAccessServices = ReturnType; export type { ApmDataAccessServicesParams } from './services/get_services'; @@ -27,3 +38,4 @@ export type { APMEventESSearchRequest, APMLogEventESSearchRequest, } from './lib/helpers'; +export type { ApmDataAccessPrivilegesCheck }; diff --git a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json index f7ac83af0922e..d4c38fddf967e 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json @@ -9,6 +9,7 @@ "@kbn/config-schema", "@kbn/core", "@kbn/i18n", + "@kbn/core-saved-objects-api-server", "@kbn/data-plugin", "@kbn/inspector-plugin", "@kbn/observability-plugin", @@ -17,6 +18,8 @@ "@kbn/apm-types", "@kbn/core-http-server-mocks", "@kbn/apm-utils", + "@kbn/core-http-server", + "@kbn/security-plugin-types-server", "@kbn/utility-types", "@kbn/elastic-agent-utils", "@kbn/observability-utils-common" diff --git a/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts b/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts index 51a1421aec918..7220f9014b477 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts @@ -95,13 +95,24 @@ export const integrationRt = rt.intersection([ export type IntegrationType = rt.TypeOf; +export const checkAndLoadIntegrationResponseRt = rt.union([ + rt.type({ isIntegration: rt.literal(false), areAssetsAvailable: rt.boolean }), + rt.type({ + isIntegration: rt.literal(true), + areAssetsAvailable: rt.literal(true), + integration: integrationRt, + }), +]); + +export type CheckAndLoadIntegrationResponse = rt.TypeOf; + export const getIntegrationsResponseRt = rt.exact( rt.type({ integrations: rt.array(integrationRt), }) ); -export type IntegrationResponse = rt.TypeOf; +export type IntegrationsResponse = rt.TypeOf; export const degradedFieldRt = rt.type({ name: rt.string, diff --git a/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts index ce74552b581b9..f6372e1dc61a2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts @@ -5,9 +5,7 @@ * 2.0. */ -export interface GetDataStreamIntegrationParams { - integrationName: string; -} +import { Integration } from '../data_streams_stats/integration'; export interface AnalyzeDegradedFieldsParams { dataStream: string; @@ -19,3 +17,13 @@ export interface UpdateFieldLimitParams { dataStream: string; newFieldLimit: number; } + +export interface CheckAndLoadIntegrationParams { + dataStream: string; +} + +export interface IntegrationType { + isIntegration: boolean; + areAssetsAvailable: boolean; + integration?: Integration; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx index 1056713ac2070..5dc8d6d367010 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx @@ -29,7 +29,11 @@ import { IncreaseFieldMappingLimit } from './increase_field_mapping_limit'; import { FieldLimitDocLink } from './field_limit_documentation_link'; import { MessageCallout } from './message_callout'; -export function FieldMappingLimit({ isIntegration }: { isIntegration: boolean }) { +export function FieldMappingLimit({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const accordionId = useGeneratedHtmlId({ prefix: increaseFieldMappingLimitTitle, }); @@ -66,7 +70,7 @@ export function FieldMappingLimit({ isIntegration }: { isIntegration: boolean }) - {isIntegration && ( + {areIntegrationAssetsAvailable && ( <> updateNewFieldLimit(newFieldLimit)} isLoading={isMitigationInProgress} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx index 34f39f25a67ec..d9ca2128521f2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx @@ -15,7 +15,7 @@ import { PossibleMitigationTitle } from './title'; export function PossibleMitigations() { const { degradedFieldAnalysis, isAnalysisInProgress } = useDegradedFields(); const { integrationDetails } = useDatasetQualityDetailsState(); - const isIntegration = Boolean(integrationDetails?.integration); + const areIntegrationAssetsAvailable = !!integrationDetails?.integration?.areAssetsAvailable; return ( !isAnalysisInProgress && ( @@ -24,7 +24,7 @@ export function PossibleMitigations() { {degradedFieldAnalysis?.isFieldLimitIssue && ( <> - + )} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx index 54bbe91f2f2e1..e8768d34cdcca 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx @@ -13,7 +13,11 @@ import { useDatasetQualityDetailsState } from '../../../../../hooks'; import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../../../common/utils/component_template_name'; import { otherMitigationsCustomComponentTemplate } from '../../../../../../common/translations'; -export function CreateEditComponentTemplateLink({ isIntegration }: { isIntegration: boolean }) { +export function CreateEditComponentTemplateLink({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const { services: { application, @@ -54,7 +58,7 @@ export function CreateEditComponentTemplateLink({ isIntegration }: { isIntegrati name, ]); - const templateUrl = isIntegration ? componentTemplatePath : indexTemplatePath; + const templateUrl = areIntegrationAssetsAvailable ? componentTemplatePath : indexTemplatePath; const onClickHandler = useCallback(async () => { const options = { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx index f931f3461fb57..34cdbe4b9b838 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx @@ -13,27 +13,27 @@ import { CreateEditPipelineLink } from './pipeline_link'; import { otherMitigationsLoadingAriaText } from '../../../../../../common/translations'; export function ManualMitigations() { - const { integrationDetails, loadingState, dataStreamSettings } = useDatasetQualityDetailsState(); - const isIntegrationPresentInSettings = dataStreamSettings?.integration; - const isIntegration = !!integrationDetails?.integration; - const { dataStreamSettingsLoading, integrationDetailsLoadings } = loadingState; - - const hasIntegrationCheckCompleted = - !dataStreamSettingsLoading && - ((isIntegrationPresentInSettings && !integrationDetailsLoadings) || - !isIntegrationPresentInSettings); + const { + integrationDetails, + loadingState: { integrationDetailsLoaded }, + } = useDatasetQualityDetailsState(); + const areIntegrationAssetsAvailable = !!integrationDetails?.integration?.areAssetsAvailable; return ( - + - + ); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx index 6179a3ed0736c..f4084c52e2efd 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { @@ -34,7 +34,11 @@ const AccordionTitle = () => ( ); -export function CreateEditPipelineLink({ isIntegration }: { isIntegration: boolean }) { +export function CreateEditPipelineLink({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const { services: { share: { @@ -50,10 +54,7 @@ export function CreateEditPipelineLink({ isIntegration }: { isIntegration: boole const { datasetDetails } = useDatasetQualityDetailsState(); const { type, name } = datasetDetails; - const pipelineName = useMemo( - () => (isIntegration ? `${type}-${name}@custom` : `${type}@custom`), - [isIntegration, type, name] - ); + const pipelineName = areIntegrationAssetsAvailable ? `${type}-${name}@custom` : `${type}@custom`; const ingestPipelineLocator = locators.get('INGEST_PIPELINES_APP_LOCATOR'); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx index 17032d7866d05..8bbc9aa085420 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx @@ -7,7 +7,7 @@ import React, { Fragment } from 'react'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import { EuiBadge, EuiFlexGroup, EuiPanel, EuiText } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiPanel, EuiSkeletonRectangle, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import { IntegrationActionsMenu } from './integration_actions_menu'; import { @@ -29,7 +29,8 @@ export function DatasetSummary() { const { dataStreamDetailsLoading, dataStreamSettingsLoading, - integrationDetailsLoadings, + integrationDetailsLoading, + integrationDetailsLoaded, integrationDashboardsLoading, } = loadingState; const formattedLastActivity = dataStreamDetails?.lastActivity @@ -39,12 +40,19 @@ export function DatasetSummary() { ? dataFormatter.convert(dataStreamSettings.createdOn) : '-'; - return ( + return !integrationDetailsLoaded ? ( + + ) : ( - - {integrationDetails.integration?.name} + + + {integrationDetails.integration.integration?.name} + ), actionsMenu: ( ), - isLoading: integrationDetailsLoadings, + isLoading: integrationDetailsLoading, }, { fieldTitle: integrationVersionText, - fieldValue: integrationDetails.integration?.version, - isLoading: integrationDetailsLoadings, + fieldValue: integrationDetails.integration.integration?.version, + isLoading: integrationDetailsLoading, }, ] : []), diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx index e45253b6405c8..60a26d4285732 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx @@ -44,7 +44,8 @@ export function Header() { sendTelemetry, }); - const pageTitle = integrationDetails?.integration?.datasets?.[datasetDetails.name] ?? title; + const pageTitle = + integrationDetails?.integration?.integration?.datasets?.[datasetDetails.name] ?? title; return !loadingState.integrationDetailsLoaded ? ( - +

        diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts index f613d3af7fdc4..4d2d838419271 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts @@ -42,7 +42,7 @@ export function useDatasetDetailsTelemetry() { breakdownField, isNonAggregatable, isBreakdownFieldEcs, - integration: integrationDetails.integration, + integration: integrationDetails.integration?.integration, }); } @@ -57,7 +57,7 @@ export function useDatasetDetailsTelemetry() { breakdownField, isNonAggregatable, isBreakdownFieldEcs, - integrationDetails.integration, + integrationDetails.integration?.integration, ]); const startTracking = useCallback(() => { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts index edd16652374a1..cfea77ff4fa39 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts @@ -51,7 +51,9 @@ export const useDatasetQualityDetailsState = () => { ); const dataStreamSettings = useSelector(service, (state) => - state.matches('initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields') + state.matches('initializing.dataStreamSettings.fetchingDataStreamDegradedFields') || + state.matches('initializing.dataStreamSettings.doneFetchingDegradedFields') || + state.matches('initializing.dataStreamSettings.errorFetchingDegradedFields') ? state.context.dataStreamSettings : undefined ); @@ -59,15 +61,17 @@ export const useDatasetQualityDetailsState = () => { const integrationDetails = { integration: useSelector(service, (state) => state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' - ) + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + ) || + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' + ) || + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done') ? state.context.integration : undefined ), dashboard: useSelector(service, (state) => - state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.done' - ) + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done') ? state.context.integrationDashboards : undefined ), @@ -77,7 +81,7 @@ export const useDatasetQualityDetailsState = () => { service, (state) => !state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.unauthorized' + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' ) ); @@ -106,14 +110,19 @@ export const useDatasetQualityDetailsState = () => { dataStreamSettingsLoading: state.matches( 'initializing.dataStreamSettings.fetchingDataStreamSettings' ), - integrationDetailsLoadings: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.fetching' - ), - integrationDetailsLoaded: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' + integrationDetailsLoading: state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.checkingAndLoadingIntegration' ), + integrationDetailsLoaded: + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + ) || + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' + ) || + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done'), integrationDashboardsLoading: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.fetching' + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' ), })); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts index fb57e6e87a74f..d499535df1662 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts @@ -81,7 +81,8 @@ export const useDegradedDocsChart = () => { useEffect(() => { const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW; const datasetTitle = - integrationDetails?.integration?.datasets?.[datasetDetails.name] ?? datasetDetails.name; + integrationDetails?.integration?.integration?.datasets?.[datasetDetails.name] ?? + datasetDetails.name; const lensAttributes = getLensAttributes({ color: euiTheme.colors.danger, @@ -95,7 +96,7 @@ export const useDegradedDocsChart = () => { euiTheme.colors.danger, setAttributes, dataStream, - integrationDetails?.integration?.datasets, + integrationDetails?.integration?.integration?.datasets, datasetDetails.name, ]); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts index 49ceb50abc3cd..47b03074fe17e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts @@ -77,10 +77,11 @@ export function useDegradedFields() { return renderedItems.find((item) => item.name === expandedDegradedField); }, [expandedDegradedField, renderedItems]); - const isDegradedFieldsLoading = useSelector(service, (state) => - state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching' - ) + const isDegradedFieldsLoading = useSelector( + service, + (state) => + state.matches('initializing.dataStreamSettings.fetchingDataStreamSettings') || + state.matches('initializing.dataStreamSettings.fetchingDataStreamDegradedFields') ); const closeDegradedFieldFlyout = useCallback( diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts index 827cd4b0a1e49..7279bed2e1859 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts @@ -8,6 +8,8 @@ import { HttpStart } from '@kbn/core/public'; import { decodeOrThrow } from '@kbn/io-ts-utils'; import { + CheckAndLoadIntegrationResponse, + checkAndLoadIntegrationResponseRt, DataStreamRolloverResponse, dataStreamRolloverResponseRt, DegradedFieldAnalysis, @@ -17,10 +19,8 @@ import { getDataStreamDegradedFieldsResponseRt, getDataStreamsDetailsResponseRt, getDataStreamsSettingsResponseRt, - getIntegrationsResponseRt, IntegrationDashboardsResponse, integrationDashboardsRT, - IntegrationResponse, UpdateFieldLimitResponse, updateFieldLimitResponseRt, } from '../../../common/api_types'; @@ -40,7 +40,7 @@ import { IDataStreamDetailsClient } from './types'; import { Integration } from '../../../common/data_streams_stats/integration'; import { AnalyzeDegradedFieldsParams, - GetDataStreamIntegrationParams, + CheckAndLoadIntegrationParams, UpdateFieldLimitParams, } from '../../../common/data_stream_details/types'; import { DatasetQualityError } from '../../../common/errors'; @@ -139,43 +139,48 @@ export class DataStreamDetailsClient implements IDataStreamDetailsClient { )(response); } - public async getIntegrationDashboards({ integration }: GetIntegrationDashboardsParams) { + public async checkAndLoadIntegration({ dataStream }: CheckAndLoadIntegrationParams) { const response = await this.http - .get( - `/internal/dataset_quality/integrations/${integration}/dashboards` + .get( + `/internal/dataset_quality/data_streams/${dataStream}/integration/check` ) .catch((error) => { - throw new DatasetQualityError(`Failed to fetch integration dashboards": ${error}`, error); + throw new DatasetQualityError( + `Failed to check if data stream belongs to an integration": ${error}`, + error + ); }); - const { dashboards } = decodeOrThrow( - integrationDashboardsRT, + const decodedResponse = decodeOrThrow( + checkAndLoadIntegrationResponseRt, (message: string) => - new DatasetQualityError(`Failed to decode integration dashboards response: ${message}"`) + new DatasetQualityError(`Failed to decode integration check response: ${message}"`) )(response); - return dashboards; + return { + ...decodedResponse, + integration: decodedResponse.isIntegration + ? Integration.create(decodedResponse.integration) + : undefined, + }; } - public async getDataStreamIntegration( - params: GetDataStreamIntegrationParams - ): Promise { - const { integrationName } = params; + public async getIntegrationDashboards({ integration }: GetIntegrationDashboardsParams) { const response = await this.http - .get('/internal/dataset_quality/integrations') + .get( + `/internal/dataset_quality/integrations/${integration}/dashboards` + ) .catch((error) => { - throw new DatasetQualityError(`Failed to fetch integrations: ${error}`, error); + throw new DatasetQualityError(`Failed to fetch integration dashboards": ${error}`, error); }); - const { integrations } = decodeOrThrow( - getIntegrationsResponseRt, + const { dashboards } = decodeOrThrow( + integrationDashboardsRT, (message: string) => - new DatasetQualityError(`Failed to decode integrations response: ${message}`) + new DatasetQualityError(`Failed to decode integration dashboards response: ${message}"`) )(response); - const integration = integrations.find((i) => i.name === integrationName); - - if (integration) return Integration.create(integration); + return dashboards; } public async analyzeDegradedField({ diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts index 6eac8bd732840..f38c68a68bff5 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts @@ -6,7 +6,6 @@ */ import { HttpStart } from '@kbn/core/public'; -import { Integration } from '../../../common/data_streams_stats/integration'; import { GetDataStreamSettingsParams, DataStreamSettings, @@ -19,7 +18,8 @@ import { } from '../../../common/data_streams_stats'; import { AnalyzeDegradedFieldsParams, - GetDataStreamIntegrationParams, + IntegrationType, + CheckAndLoadIntegrationParams, UpdateFieldLimitParams, } from '../../../common/data_stream_details/types'; import { @@ -49,10 +49,8 @@ export interface IDataStreamDetailsClient { getDataStreamDegradedFieldValues( params: GetDataStreamDegradedFieldValuesPathParams ): Promise; + checkAndLoadIntegration(params: CheckAndLoadIntegrationParams): Promise; getIntegrationDashboards(params: GetIntegrationDashboardsParams): Promise; - getDataStreamIntegration( - params: GetDataStreamIntegrationParams - ): Promise; analyzeDegradedField(params: AnalyzeDegradedFieldsParams): Promise; setNewFieldLimit(params: UpdateFieldLimitParams): Promise; rolloverDataStream(params: { dataStream: string }): Promise; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts index 8e218819315b2..5e4790309a07f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts @@ -17,7 +17,7 @@ import { getDataStreamTotalDocsResponseRt, getIntegrationsResponseRt, getNonAggregatableDatasetsRt, - IntegrationResponse, + IntegrationsResponse, NonAggregatableDatasets, } from '../../../common/api_types'; import { @@ -132,7 +132,7 @@ export class DataStreamsStatsClient implements IDataStreamsStatsClient { public async getIntegrations(): Promise { const response = await this.http - .get('/internal/dataset_quality/integrations') + .get('/internal/dataset_quality/integrations') .catch((error) => { throw new DatasetQualityError(`Failed to fetch integrations: ${error}`, error); }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts index f5fdd063492a3..fbd2dd1dc1913 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts @@ -44,17 +44,10 @@ export const fetchIntegrationDashboardsFailedNotifier = (toasts: IToasts, error: }); }; -export const fetchDataStreamIntegrationFailedNotifier = ( - toasts: IToasts, - error: Error, - integrationName?: string -) => { +export const fetchDataStreamIntegrationFailedNotifier = (toasts: IToasts, error: Error) => { toasts.addDanger({ title: i18n.translate('xpack.datasetQuality.details.fetchIntegrationsFailed', { - defaultMessage: "We couldn't get {integrationName} integration info.", - values: { - integrationName, - }, + defaultMessage: "We couldn't get integration info.", }), text: error.message, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts index 8ac65a7dca4a7..363919b35f65e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts @@ -28,6 +28,8 @@ import { UpdateFieldLimitResponse, } from '../../../common/api_types'; import { fetchNonAggregatableDatasetsFailedNotifier } from '../common/notifications'; + +import { IntegrationType } from '../../../common/data_stream_details'; import { fetchDataStreamDetailsFailedNotifier, assertBreakdownFieldEcsFailedNotifier, @@ -37,7 +39,6 @@ import { updateFieldLimitFailedNotifier, rolloverDataStreamFailedNotifier, } from './notifications'; -import { Integration } from '../../../common/data_streams_stats/integration'; export const createPureDatasetQualityDetailsControllerStateMachine = ( initialContext: DatasetQualityDetailsControllerContext @@ -151,7 +152,7 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( invoke: { src: 'loadDataStreamSettings', onDone: { - target: 'loadingIntegrationsAndDegradedFields', + target: 'fetchingDataStreamDegradedFields', actions: ['storeDataStreamSettings'], }, onError: [ @@ -160,111 +161,49 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( cond: 'isIndexNotFoundError', }, { - target: 'done', + target: 'errorFetchingDataStreamSettings', actions: ['notifyFetchDataStreamSettingsFailed'], }, ], }, }, - loadingIntegrationsAndDegradedFields: { - type: 'parallel', - states: { - dataStreamDegradedFields: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDegradedFields', - onDone: { - target: 'done', - actions: ['storeDegradedFields', 'raiseDegradedFieldsLoaded'], - }, - onError: [ - { - target: '#DatasetQualityDetailsController.indexNotFound', - cond: 'isIndexNotFoundError', - }, - { - target: 'done', - }, - ], - }, - }, - done: { - on: { - UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: { - target: 'done', - actions: ['storeDegradedFieldTableOptions'], - }, - OPEN_DEGRADED_FIELD_FLYOUT: { - target: - '#DatasetQualityDetailsController.initializing.degradedFieldFlyout.open', - actions: [ - 'storeExpandedDegradedField', - 'resetFieldLimitServerResponse', - ], - }, - TOGGLE_CURRENT_QUALITY_ISSUES: { - target: 'fetching', - actions: ['toggleCurrentQualityIssues'], - }, - }, - }, - }, + errorFetchingDataStreamSettings: {}, + fetchingDataStreamDegradedFields: { + invoke: { + src: 'loadDegradedFields', + onDone: { + target: 'doneFetchingDegradedFields', + actions: ['storeDegradedFields', 'raiseDegradedFieldsLoaded'], }, - integrationDetails: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDataStreamIntegration', - onDone: { - target: 'done', - actions: ['storeDataStreamIntegration'], - }, - onError: { - target: 'done', - actions: ['notifyFetchDatasetIntegrationsFailed'], - }, - }, - }, - done: {}, + onError: [ + { + target: '#DatasetQualityDetailsController.indexNotFound', + cond: 'isIndexNotFoundError', }, - }, - integrationDashboards: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadIntegrationDashboards', - onDone: { - target: 'done', - actions: ['storeIntegrationDashboards'], - }, - onError: [ - { - target: 'unauthorized', - cond: 'checkIfActionForbidden', - }, - { - target: 'done', - actions: ['notifyFetchIntegrationDashboardsFailed'], - }, - ], - }, - }, - done: {}, - unauthorized: { - type: 'final', - }, + { + target: 'errorFetchingDegradedFields', }, - }, + ], }, - onDone: { - target: 'done', + }, + doneFetchingDegradedFields: { + on: { + UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: { + target: 'doneFetchingDegradedFields', + actions: ['storeDegradedFieldTableOptions'], + }, + OPEN_DEGRADED_FIELD_FLYOUT: { + target: + '#DatasetQualityDetailsController.initializing.degradedFieldFlyout.open', + actions: ['storeExpandedDegradedField', 'resetFieldLimitServerResponse'], + }, + TOGGLE_CURRENT_QUALITY_ISSUES: { + target: 'fetchingDataStreamDegradedFields', + actions: ['toggleCurrentQualityIssues'], + }, }, }, - done: {}, + errorFetchingDegradedFields: {}, }, on: { UPDATE_TIME_RANGE: { @@ -272,6 +211,54 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( }, }, }, + checkAndLoadIntegrationAndDashboards: { + initial: 'checkingAndLoadingIntegration', + states: { + checkingAndLoadingIntegration: { + invoke: { + src: 'checkAndLoadIntegration', + onDone: [ + { + target: 'loadingIntegrationDashboards', + actions: 'storeDataStreamIntegration', + cond: 'isDataStreamIsPartOfIntegration', + }, + { + actions: 'storeDataStreamIntegration', + target: 'done', + }, + ], + onError: { + target: 'done', + actions: ['notifyFetchDatasetIntegrationsFailed'], + }, + }, + }, + loadingIntegrationDashboards: { + invoke: { + src: 'loadIntegrationDashboards', + onDone: { + target: 'done', + actions: ['storeIntegrationDashboards'], + }, + onError: [ + { + target: 'unauthorizedToLoadDashboards', + cond: 'checkIfActionForbidden', + }, + { + target: 'done', + actions: ['notifyFetchIntegrationDashboardsFailed'], + }, + ], + }, + }, + unauthorizedToLoadDashboards: { + type: 'final', + }, + done: {}, + }, + }, degradedFieldFlyout: { initial: 'pending', states: { @@ -522,7 +509,7 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( } : {}; }), - storeDataStreamIntegration: assign((context, event: DoneInvokeEvent) => { + storeDataStreamIntegration: assign((context, event: DoneInvokeEvent) => { return 'data' in event ? { integration: event.data, @@ -602,6 +589,14 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( !event.data.isLatestBackingIndexUpdated ); }, + isDataStreamIsPartOfIntegration: (_, event) => { + return ( + 'data' in event && + typeof event.data === 'object' && + 'isIntegration' in event.data && + event.data.isIntegration + ); + }, }, } ); @@ -634,9 +629,7 @@ export const createDatasetQualityDetailsControllerStateMachine = ({ notifyFetchIntegrationDashboardsFailed: (_context, event: DoneInvokeEvent) => fetchIntegrationDashboardsFailedNotifier(toasts, event.data), notifyFetchDatasetIntegrationsFailed: (context, event: DoneInvokeEvent) => { - const integrationName = - 'dataStreamSettings' in context ? context.dataStreamSettings?.integration : undefined; - return fetchDataStreamIntegrationFailedNotifier(toasts, event.data, integrationName); + return fetchDataStreamIntegrationFailedNotifier(toasts, event.data); }, notifySaveNewFieldLimitError: (_context, event: DoneInvokeEvent) => updateFieldLimitFailedNotifier(toasts, event.data), @@ -735,18 +728,15 @@ export const createDatasetQualityDetailsControllerStateMachine = ({ dataStream: context.dataStream, }); }, - loadDataStreamIntegration: (context) => { - if ('dataStreamSettings' in context && context.dataStreamSettings?.integration) { - return dataStreamDetailsClient.getDataStreamIntegration({ - integrationName: context.dataStreamSettings.integration, - }); - } - return Promise.resolve(); + checkAndLoadIntegration: (context) => { + return dataStreamDetailsClient.checkAndLoadIntegration({ + dataStream: context.dataStream, + }); }, loadIntegrationDashboards: (context) => { - if ('dataStreamSettings' in context && context.dataStreamSettings?.integration) { + if ('integration' in context && context.integration && context.integration.integration) { return dataStreamDetailsClient.getIntegrationDashboards({ - integration: context.dataStreamSettings.integration, + integration: context.integration.integration.name, }); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts index cdebcfbe53d86..d33e5c4f0415e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts @@ -20,7 +20,7 @@ import { UpdateFieldLimitResponse, } from '../../../common/api_types'; import { TableCriteria, TimeRangeConfig } from '../../../common/types'; -import { Integration } from '../../../common/data_streams_stats/integration'; +import { IntegrationType } from '../../../common/data_stream_details'; export interface DataStream { name: string; @@ -53,7 +53,7 @@ export interface WithDefaultControllerState { breakdownField?: string; isBreakdownFieldEcs?: boolean; isIndexNotFoundError?: boolean; - integration?: Integration; + integration?: IntegrationType; expandedDegradedField?: string; isNonAggregatable?: boolean; fieldLimit?: FieldLimit; @@ -84,8 +84,11 @@ export interface WithDataStreamSettings { } export interface WithIntegration { - integration: Integration; - integrationDashboards?: Dashboard[]; + integration: IntegrationType; +} + +export interface WithIntegrationDashboards { + integrationDashboards: Dashboard[]; } export interface WithDegradedFieldValues { @@ -116,15 +119,14 @@ export type DatasetQualityDetailsControllerTypeState = value: | 'initializing' | 'initializing.nonAggregatableDataset.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching' + | 'initializing.dataStreamDetails.fetching' | 'initializing.dataStreamSettings.fetchingDataStreamSettings' - | 'initializing.dataStreamDetails.fetching'; + | 'initializing.dataStreamSettings.errorFetchingDataStreamSettings' + | 'initializing.checkAndLoadIntegrationAndDashboards.checkingAndLoadingIntegration'; context: WithDefaultControllerState; } | { - value: - | 'initializing.nonAggregatableDataset.done' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching'; + value: 'initializing.nonAggregatableDataset.done'; context: WithDefaultControllerState & WithNonAggregatableDatasetStatus; } | { @@ -139,25 +141,25 @@ export type DatasetQualityDetailsControllerTypeState = value: 'initializing.checkBreakdownFieldIsEcs.done'; context: WithDefaultControllerState & WithBreakdownInEcsCheck; } - | { - value: 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.done'; - context: WithDefaultControllerState & - WithNonAggregatableDatasetStatus & - WithDegradedFieldsData; - } | { value: - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.unauthorized'; + | 'initializing.dataStreamSettings.fetchingDataStreamDegradedFields' + | 'initializing.dataStreamSettings.errorFetchingDegradedFields'; context: WithDefaultControllerState & WithDataStreamSettings; } + | { + value: 'initializing.dataStreamSettings.doneFetchingDegradedFields'; + context: WithDefaultControllerState & WithDataStreamSettings & WithDegradedFieldsData; + } | { value: - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.done'; - context: WithDefaultControllerState & WithDataStreamSettings & WithIntegration; + | 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + | 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards'; + context: WithDefaultControllerState & WithIntegration; + } + | { + value: 'initializing.checkAndLoadIntegrationAndDashboards.done'; + context: WithDefaultControllerState & WithIntegration & WithIntegrationDashboards; } | { value: 'initializing.degradedFieldFlyout.open'; @@ -233,8 +235,8 @@ export type DatasetQualityDetailsControllerEvent = | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent - | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent - | DoneInvokeEvent; + | DoneInvokeEvent + | DoneInvokeEvent; diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.ts new file mode 100644 index 0000000000000..a6606028b6cfc --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.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 type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { PackageClient } from '@kbn/fleet-plugin/server'; +import { Logger } from '@kbn/logging'; +import { validateCustomComponentTemplate } from './validate_custom_component_template'; +import { getIntegration, getIntegrations } from '../../integrations/get_integrations'; +import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../common/utils/component_template_name'; +import { CheckAndLoadIntegrationResponse } from '../../../../common/api_types'; +import { dataStreamService } from '../../../services'; + +// The function works on 2 conditions: +// 1. It checks if integration name is present in meta field response of the datastream. +// If yes, it considers it to be an integration. No further checks +// 2. If not, then it does the various checks +export async function checkAndLoadIntegration({ + esClient, + packageClient, + logger, + dataStream, +}: { + esClient: ElasticsearchClient; + packageClient: PackageClient; + logger: Logger; + dataStream: string; +}): Promise { + const [dataStreamInfo] = await dataStreamService.getMatchingDataStreams(esClient, dataStream); + + const indexTemplate = dataStreamInfo?.template; + const isManaged = dataStreamInfo?._meta?.managed; + + const integrationNameFromDataStream = dataStreamInfo?._meta?.package?.name; + + // Index template must be present and isManaged should be true or + // integration name should be present + // Else it's not an integration + if ((!indexTemplate || !isManaged) && !integrationNameFromDataStream) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + // If integration name is present, then we find and return the integration + if (integrationNameFromDataStream) { + try { + const integrationDetailsMatchingDataStream = await getIntegration({ + packageClient, + logger, + packageName: integrationNameFromDataStream, + }); + + if (integrationDetailsMatchingDataStream) { + return { + isIntegration: true, + integration: integrationDetailsMatchingDataStream, + areAssetsAvailable: true, + }; + } + } catch (e) { + // This should ideally not happen. As integration name is present in Data stream + // meta response but the integration itself is not found + // Worst case i could think of is, may be the integration is deleted from the + // system at a later point of time + return { isIntegration: false, areAssetsAvailable: false }; + } + } + + // cleaning the index template name as some have @template suffix + const indexTemplateNameWithoutSuffix = getComponentTemplatePrefixFromIndexTemplate(indexTemplate); + + // Check if index template name has both type and dataset part + const isDedicatedComponentTemplate = indexTemplateNameWithoutSuffix.split('-').length === 2; + + // If only 1 part exists, then it's not a dedicated index template + // Data stream name must starts with this index template, then it's a dedicated index template else not + if (!isDedicatedComponentTemplate || !dataStream.startsWith(indexTemplateNameWithoutSuffix)) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + const isValidCustomComponentTemplate = await validateCustomComponentTemplate({ + esClient, + indexTemplateName: indexTemplate, + }); + + if (!isValidCustomComponentTemplate) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + const datasetName = indexTemplateNameWithoutSuffix.split('-')[1]; + + const allIntegrations = await getIntegrations({ packageClient, logger }); + const integrationFromDataset = allIntegrations.find( + (integration) => datasetName in (integration?.datasets ?? {}) + ); + + if (integrationFromDataset) { + return { isIntegration: true, integration: integrationFromDataset, areAssetsAvailable: true }; + } + + // Since the logic reached the last statement, it means it passed all checks for assets being available + return { isIntegration: false, areAssetsAvailable: true }; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts new file mode 100644 index 0000000000000..13213814935f1 --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { createDatasetQualityESClient } from '../../../utils'; +import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../common/utils/component_template_name'; + +export async function validateCustomComponentTemplate({ + esClient, + indexTemplateName, +}: { + esClient: ElasticsearchClient; + indexTemplateName: string; +}): Promise { + const datasetQualityESClient = createDatasetQualityESClient(esClient); + // cleaning the index template name as some have @template suffix + const componentTemplateName = getComponentTemplatePrefixFromIndexTemplate(indexTemplateName); + + try { + const { index_templates: indexTemplates } = await datasetQualityESClient.indexTemplates({ + name: indexTemplateName, + }); + + return indexTemplates.some((template) => + template.index_template.composed_of.includes(componentTemplateName + '@custom') + ); + } catch (error) { + return false; + } +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts index 288eff11b92a8..0ca2ae94214e8 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts @@ -16,38 +16,12 @@ import { rangeQuery } from '@kbn/observability-plugin/server'; import { MAX_HOSTS_METRIC_VALUE } from '../../../../common/constants'; import { _IGNORED } from '../../../../common/es_fields'; -import { DataStreamDetails, DataStreamSettings } from '../../../../common/api_types'; +import { DataStreamDetails } from '../../../../common/api_types'; import { createDatasetQualityESClient } from '../../../utils'; -import { dataStreamService, datasetQualityPrivileges } from '../../../services'; +import { datasetQualityPrivileges } from '../../../services'; import { getDataStreams } from '../get_data_streams'; import { getDataStreamsMeteringStats } from '../get_data_streams_metering_stats'; -export async function getDataStreamSettings({ - esClient, - dataStream, -}: { - esClient: ElasticsearchClient; - dataStream: string; -}): Promise { - const [createdOn, [dataStreamInfo], datasetUserPrivileges] = await Promise.all([ - getDataStreamCreatedOn(esClient, dataStream), - dataStreamService.getMatchingDataStreams(esClient, dataStream), - datasetQualityPrivileges.getDatasetPrivileges(esClient, dataStream), - ]); - - const integration = dataStreamInfo?._meta?.package?.name; - const lastBackingIndex = dataStreamInfo?.indices?.slice(-1)[0]; - const indexTemplate = dataStreamInfo?.template; - - return { - createdOn, - integration, - datasetUserPrivileges, - lastBackingIndexName: lastBackingIndex?.index_name, - indexTemplate, - }; -} - export async function getDataStreamDetails({ esClient, dataStream, @@ -118,16 +92,6 @@ export async function getDataStreamDetails({ } } -async function getDataStreamCreatedOn(esClient: ElasticsearchClient, dataStream: string) { - const indexSettings = await dataStreamService.getDataStreamIndexSettings(esClient, dataStream); - - const indexesList = Object.values(indexSettings); - - return indexesList - .map((index) => Number(index.settings?.index?.creation_date)) - .sort((a, b) => a - b)[0]; -} - type TermAggregation = Record; const MAX_HOSTS = MAX_HOSTS_METRIC_VALUE + 1; // Adding 1 so that we can show e.g. '50+' diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts new file mode 100644 index 0000000000000..d9d22d326bffb --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { dataStreamService } from '../../../services'; + +export async function getDataStreamCreatedOn(esClient: ElasticsearchClient, dataStream: string) { + const indexSettings = await dataStreamService.getDataStreamIndexSettings(esClient, dataStream); + + const indexesList = Object.values(indexSettings); + + return indexesList + .map((index) => Number(index.settings?.index?.creation_date)) + .sort((a, b) => a - b)[0]; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.ts new file mode 100644 index 0000000000000..8044c8a5abf6a --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.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 type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { datasetQualityPrivileges, dataStreamService } from '../../../services'; +import { DataStreamSettings } from '../../../../common/api_types'; +import { getDataStreamCreatedOn } from './get_datastream_created_on'; + +export async function getDataStreamSettings({ + esClient, + dataStream, +}: { + esClient: ElasticsearchClient; + dataStream: string; +}): Promise { + const [createdOn, [dataStreamInfo], datasetUserPrivileges] = await Promise.all([ + getDataStreamCreatedOn(esClient, dataStream), + dataStreamService.getMatchingDataStreams(esClient, dataStream), + datasetQualityPrivileges.getDatasetPrivileges(esClient, dataStream), + ]); + + const integration = dataStreamInfo?._meta?.package?.name; + const lastBackingIndex = dataStreamInfo?.indices?.at(-1); + const indexTemplate = dataStreamInfo?.template; + + return { + createdOn, + integration, + datasetUserPrivileges, + lastBackingIndexName: lastBackingIndex?.index_name, + indexTemplate, + }; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts index 3a60f0b9a8ef3..c8ed3296908e3 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts @@ -18,11 +18,12 @@ import { DataStreamDocsStat, UpdateFieldLimitResponse, DataStreamRolloverResponse, + CheckAndLoadIntegrationResponse, } from '../../../common/api_types'; import { rangeRt, typeRt, typesRt } from '../../types/default_api_types'; import { createDatasetQualityServerRoute } from '../create_datasets_quality_server_route'; import { datasetQualityPrivileges } from '../../services'; -import { getDataStreamDetails, getDataStreamSettings } from './get_data_stream_details'; +import { getDataStreamDetails } from './get_data_stream_details'; import { getDataStreams } from './get_data_streams'; import { getDataStreamsStats } from './get_data_streams_stats'; import { getDegradedDocsPaginated } from './get_degraded_docs'; @@ -34,6 +35,8 @@ import { getDataStreamsMeteringStats } from './get_data_streams_metering_stats'; import { getAggregatedDatasetPaginatedResults } from './get_dataset_aggregated_paginated_results'; import { updateFieldLimit } from './update_field_limit'; import { createDatasetQualityESClient } from '../../utils'; +import { getDataStreamSettings } from './get_datastream_settings'; +import { checkAndLoadIntegration } from './check_and_load_integration'; const statsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/stats', @@ -293,6 +296,38 @@ const dataStreamSettingsRoute = createDatasetQualityServerRoute({ }, }); +const checkAndLoadIntegrationRoute = createDatasetQualityServerRoute({ + endpoint: 'GET /internal/dataset_quality/data_streams/{dataStream}/integration/check', + params: t.type({ + path: t.type({ + dataStream: t.string, + }), + }), + options: { + tags: [], + }, + async handler(resources): Promise { + const { context, params, plugins, logger } = resources; + const { dataStream } = params.path; + const coreContext = await context.core; + + // Query dataStreams as the current user as the Kibana internal user may not have all the required permissions + const esClient = coreContext.elasticsearch.client.asCurrentUser; + + const fleetPluginStart = await plugins.fleet.start(); + const packageClient = fleetPluginStart.packageService.asInternalUser; + + const integration = await checkAndLoadIntegration({ + esClient, + packageClient, + logger, + dataStream, + }); + + return integration; + }, +}); + const dataStreamDetailsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/{dataStream}/details', params: t.type({ @@ -418,6 +453,7 @@ export const dataStreamsRouteRepository = { ...degradedFieldValuesRoute, ...dataStreamDetailsRoute, ...dataStreamSettingsRoute, + ...checkAndLoadIntegrationRoute, ...analyzeDegradedFieldRoute, ...updateFieldLimitRoute, ...rolloverDataStream, diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts index f377ea1e2642c..d00831a58aa7f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts @@ -11,7 +11,7 @@ import { createDatasetQualityESClient } from '../../../utils'; import { updateComponentTemplate } from './update_component_template'; import { updateLastBackingIndexSettings } from './update_settings_last_backing_index'; import { UpdateFieldLimitResponse } from '../../../../common/api_types'; -import { getDataStreamSettings } from '../get_data_stream_details'; +import { getDataStreamSettings } from '../get_datastream_settings'; export async function updateFieldLimit({ esClient, diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts index 10e89db800a20..b8bf8719783ce 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts @@ -8,9 +8,29 @@ import { Logger } from '@kbn/core/server'; import { PackageClient } from '@kbn/fleet-plugin/server'; import { PackageNotFoundError } from '@kbn/fleet-plugin/server/errors'; -import { PackageListItem, RegistryDataStream } from '@kbn/fleet-plugin/common'; +import { PackageInfo, RegistryDataStream } from '@kbn/fleet-plugin/common'; import { IntegrationType } from '../../../common/api_types'; +export async function getIntegration({ + packageClient, + logger, + packageName, +}: { + packageClient: PackageClient; + logger: Logger; + packageName: string; +}): Promise { + const latestPackage = await packageClient.getLatestPackageInfo(packageName); + + return { + name: latestPackage.name, + title: latestPackage.title, + version: latestPackage.version, + icons: latestPackage.icons, + datasets: await getDatasets({ packageClient, logger, pkg: latestPackage }), + }; +} + export async function getIntegrations(options: { packageClient: PackageClient; logger: Logger; @@ -36,7 +56,7 @@ export async function getIntegrations(options: { const getDatasets = async (options: { packageClient: PackageClient; logger: Logger; - pkg: PackageListItem; + pkg: Pick; }) => { const { packageClient, logger, pkg } = options; diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts b/x-pack/plugins/observability_solution/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts index 879b02f8a93c5..5f36a8a4204f2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts @@ -24,14 +24,18 @@ export async function callKibana({ ...options, baseURL: baseUrl, auth: { username, password }, - headers: { 'kbn-xsrf': 'true', ...options.headers }, + headers: { 'kbn-xsrf': 'true', 'x-elastic-internal-origin': 'kibana', ...options.headers }, }); return data; } const getBaseUrl = once(async (kibanaHostname: string) => { try { - await axios.request({ url: kibanaHostname, maxRedirects: 0 }); + await axios.request({ + url: kibanaHostname, + maxRedirects: 0, + headers: { 'x-elastic-internal-origin': 'kibana' }, + }); } catch (e) { if (isAxiosError(e)) { const location = e.response?.headers?.location ?? ''; diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts b/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts index 8a78b4163da95..cb6c963435f1e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts @@ -13,6 +13,8 @@ import { FieldCapsRequest, FieldCapsResponse, Indices, + IndicesGetIndexTemplateRequest, + IndicesGetIndexTemplateResponse, IndicesGetMappingResponse, IndicesGetSettingsResponse, IndicesPutSettingsRequest, @@ -63,5 +65,10 @@ export function createDatasetQualityESClient(esClient: ElasticsearchClient) { rollover(params: { alias: string }): Promise { return esClient.indices.rollover(params); }, + indexTemplates( + params: IndicesGetIndexTemplateRequest + ): Promise { + return esClient.indices.getIndexTemplate(params); + }, }; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json index 8576b08bd9479..57b159cdbd295 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json +++ b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json @@ -61,7 +61,8 @@ "@kbn/rison", "@kbn/task-manager-plugin", "@kbn/core-application-browser", - "@kbn/field-utils" + "@kbn/field-utils", + "@kbn/logging" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx b/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx index 8c978db6f6751..59740fb8f8135 100644 --- a/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx +++ b/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx @@ -101,17 +101,29 @@ function EntitySourceForm({ /> + + + + onFieldChange(index, 'display_name', e.target.value)} + /> + + ); } interface EntitySource { id: string; - index_patterns?: string[]; - identity_fields?: string[]; - metadata_fields?: string[]; - filters?: string[]; + index_patterns: string[]; + identity_fields: string[]; + metadata_fields: string[]; + filters: string[]; timestamp_field?: string; + display_name?: string; } const newEntitySource = ({ @@ -126,7 +138,7 @@ const newEntitySource = ({ metadataFields?: string[]; filters?: string[]; timestampField?: string; -}) => ({ +}): EntitySource => ({ id: uuid(), index_patterns: indexPatterns, identity_fields: identityFields, @@ -320,6 +332,10 @@ export function EntityManagerOverviewPage() { field: 'entity.id', name: 'entity.id', }, + { + field: 'entity.display_name', + name: 'entity.display_name', + }, { field: 'entity.type', name: 'entity.type', @@ -329,16 +345,10 @@ export function EntityManagerOverviewPage() { name: 'entity.last_seen_timestamp', }, ...Array.from(new Set(entitySources.flatMap((source) => source.identity_fields))).map( - (field) => ({ - field, - name: field, - }) + (field) => ({ field, name: field }) ), ...Array.from(new Set(entitySources.flatMap((source) => source.metadata_fields))).map( - (field) => ({ - field: `metadata.${field}`, - name: `metadata.${field}`, - }) + (field) => ({ field, name: field }) ), ]} /> diff --git a/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts index b8410a478b6f8..2ae0e0b00a2dd 100644 --- a/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts @@ -10,7 +10,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; -export const LOG_DOCUMENT_COUNT_RULE_TYPE_ID = 'logs.alert.document.count'; +export { LOG_THRESHOLD_ALERT_TYPE_ID as LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '@kbn/rule-data-utils'; const ThresholdTypeRT = rt.keyof({ count: null, diff --git a/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts b/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts index b5a3c084c47cb..d1adb75d51134 100644 --- a/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts +++ b/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts @@ -8,16 +8,12 @@ import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/ import { InventoryItemType, SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator'; +export { INFRA_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { SnapshotCustomMetricInput } from '../../http_api'; export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold'; export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; -export enum InfraRuleType { - MetricThreshold = 'metrics.alert.threshold', - InventoryThreshold = 'metrics.alert.inventory.threshold', -} - export enum Aggregators { COUNT = 'count', AVERAGE = 'avg', diff --git a/x-pack/plugins/observability_solution/infra/common/constants.ts b/x-pack/plugins/observability_solution/infra/common/constants.ts index 482406171a673..c86d39cddb3fb 100644 --- a/x-pack/plugins/observability_solution/infra/common/constants.ts +++ b/x-pack/plugins/observability_solution/infra/common/constants.ts @@ -5,14 +5,25 @@ * 2.0. */ +import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; + export const METRICS_INDEX_PATTERN = 'metrics-*,metricbeat-*'; export const LOGS_INDEX_PATTERN = 'logs-*,filebeat-*,kibana_sample_data_logs*'; export const METRICS_APP = 'metrics'; export const LOGS_APP = 'logs'; -export const METRICS_FEATURE_ID = 'infrastructure'; -export const INFRA_ALERT_FEATURE_ID = 'infrastructure'; -export const LOGS_FEATURE_ID = 'logs'; +export const METRICS_FEATURE_ID = AlertConsumers.INFRASTRUCTURE; +export const INFRA_ALERT_FEATURE_ID = AlertConsumers.INFRASTRUCTURE; +export const LOGS_FEATURE_ID = AlertConsumers.LOGS; + +export const INFRA_ALERT_CONSUMERS: ValidFeatureId[] = [ + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.OBSERVABILITY, + AlertConsumers.LOGS, + AlertConsumers.SLO, + AlertConsumers.APM, + AlertConsumers.ALERTS, +]; export type InfraFeatureId = typeof METRICS_FEATURE_ID | typeof LOGS_FEATURE_ID; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts index ca56a58875220..01da12c5f59ad 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts @@ -62,7 +62,7 @@ const containerDefaultActions = ( return { actions: { primary: { - href: locator?.getRedirectUrl({ category: OnboardingFlow.Infra }), + href: locator?.getRedirectUrl({ category: OnboardingFlow.Hosts }), label: defaultPrimaryActionLabel, }, link: { diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx index f49fa026892b1..65d19f7693740 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx @@ -14,6 +14,7 @@ import { MetricsTemplate } from './metrics_template'; import { DockerCharts, KubernetesContainerCharts } from '../../charts'; import { DOCKER_METRIC_TYPES, INTEGRATIONS, KUBERNETES_METRIC_TYPES } from '../../constants'; import { useIntegrationCheck } from '../../hooks/use_integration_check'; +import { AddMetricsCallout } from '../../add_metrics_callout'; export const ContainerMetrics = () => { const ref = useRef(null); @@ -29,7 +30,7 @@ export const ContainerMetrics = () => { }); if (!isDockerContainer && !isKubernetesContainer) { - return null; + return ; } return ( diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx index 304e67a0debde..dc4d78baeb5a1 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx @@ -75,7 +75,7 @@ export const AlertsSummaryContent = ({ )} diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx index e4f0eee51dbc0..9ace5606599d7 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -27,8 +27,6 @@ import { AddMetricsCallout } from '../../add_metrics_callout'; import { AddMetricsCalloutKey } from '../../add_metrics_callout/constants'; import { useEntitySummary } from '../../hooks/use_entity_summary'; import { isMetricsSignal } from '../../utils/get_data_stream_types'; -import { INTEGRATIONS } from '../../constants'; -import { useIntegrationCheck } from '../../hooks/use_integration_check'; export const Overview = () => { const { dateRange } = useDatePickerContext(); @@ -50,10 +48,6 @@ export const Overview = () => { `infra.dismissedAddMetricsCallout.${addMetricsCalloutId}`, false ); - const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker }); - const isKubernetesContainer = useIntegrationCheck({ - dependsOn: INTEGRATIONS.kubernetesContainer, - }); const metadataSummarySection = isFullPageView ? ( @@ -74,13 +68,7 @@ export const Overview = () => { return false; } - const { type } = asset; - const baseCondition = !isMetricsSignal(dataStreams); - - const isRelevantContainer = - type === 'container' && (isDockerContainer || isKubernetesContainer); - - return baseCondition && (type === 'host' || isRelevantContainer); + return !isMetricsSignal(dataStreams); }; const showAddMetricsCallout = shouldShowCallout(); diff --git a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx index b244ff12222d6..56d69fa9b6c7c 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx @@ -25,6 +25,12 @@ import { ChartLoadError } from './chart_load_error'; import { HOST_MISSING_FIELDS } from '../../common/visualizations/constants'; const MIN_HEIGHT = 300; +const DEFAULT_DISABLED_ACTIONS = [ + 'ACTION_CUSTOMIZE_PANEL', + 'ACTION_EXPORT_CSV', + 'embeddable_addToExistingCase', + 'create-ml-ad-job-action', +]; export type LensChartProps = BaseChartProps & Pick & { @@ -33,6 +39,8 @@ export type LensChartProps = BaseChartProps & description?: string; } & { lensAttributes: UseLensAttributesParams; + withDefaultActions?: boolean; + disabledActions?: string[]; }; export const LensChart = React.memo( @@ -52,6 +60,8 @@ export const LensChart = React.memo( height = MIN_HEIGHT, loading = false, lensAttributes, + withDefaultActions = true, + disabledActions = DEFAULT_DISABLED_ACTIONS, }: LensChartProps) => { const { formula, attributes, getExtraActions, error } = useLensAttributes(lensAttributes); @@ -122,6 +132,8 @@ export const LensChart = React.memo( dateRange={dateRange} disableTriggers={disableTriggers} extraActions={extraActions} + withDefaultActions={withDefaultActions} + disabledActions={disabledActions} filters={filters} hidePanelTitles={hidePanelTitles} loading={isLoading} diff --git a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx index 01d409fc9a1ac..01ce60b593462 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx @@ -93,7 +93,6 @@ export const LensWrapper = ({

        { }; describe('useAlertsCount', () => { - const featureIds: ValidFeatureId[] = ['infrastructure']; + const ruleTypeIds = ['metrics.alert.inventory.threshold']; + const consumers = ['foo']; beforeAll(() => { mockUseKibana(); @@ -66,7 +67,7 @@ describe('useAlertsCount', () => { it('should return the mocked data from API', async () => { mockedPostAPI.mockResolvedValue(mockedAlertsCountResponse); - const { result } = renderHook(() => useAlertsCount({ featureIds })); + const { result } = renderHook(() => useAlertsCount({ ruleTypeIds })); expect(result.current.loading).toBe(true); expect(result.current.alertsCount).toEqual(undefined); @@ -90,7 +91,8 @@ describe('useAlertsCount', () => { renderHook(() => useAlertsCount({ - featureIds, + ruleTypeIds, + consumers, query, }) ); @@ -101,7 +103,8 @@ describe('useAlertsCount', () => { terms: { field: ALERT_STATUS }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query, size: 0, }); @@ -118,7 +121,7 @@ describe('useAlertsCount', () => { const error = new Error('Fetch Alerts Count Failed'); mockedPostAPI.mockRejectedValueOnce(error); - const { result } = renderHook(() => useAlertsCount({ featureIds })); + const { result } = renderHook(() => useAlertsCount({ ruleTypeIds })); await waitFor(() => expect(result.current.error?.message).toMatch(error.message)); }); diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts index 5c602d09b7d23..aab542d597f92 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts @@ -12,17 +12,19 @@ import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common/const import { estypes } from '@elastic/elasticsearch'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { HttpSetup } from '@kbn/core/public'; -import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, ValidFeatureId } from '@kbn/rule-data-utils'; +import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; import { InfraClientCoreStart } from '../types'; interface UseAlertsCountProps { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; query?: estypes.QueryDslQueryContainer; } interface FetchAlertsCountParams { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; query?: estypes.QueryDslQueryContainer; http: HttpSetup; signal: AbortSignal; @@ -35,7 +37,7 @@ export interface AlertsCount { const ALERT_STATUS = 'kibana.alert.status'; -export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { +export function useAlertsCount({ ruleTypeIds, consumers, query }: UseAlertsCountProps) { const { http } = useKibana().services; const abortCtrlRef = useRef(new AbortController()); @@ -45,13 +47,14 @@ export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { abortCtrlRef.current.abort(); abortCtrlRef.current = new AbortController(); return fetchAlertsCount({ - featureIds, + ruleTypeIds, + consumers, query, http, signal: abortCtrlRef.current.signal, }); }, - [featureIds, query, http], + [ruleTypeIds, query, http], { loading: true } ); @@ -70,7 +73,8 @@ export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { } async function fetchAlertsCount({ - featureIds, + ruleTypeIds, + consumers, http, query, signal, @@ -84,7 +88,8 @@ async function fetchAlertsCount({ terms: { field: ALERT_STATUS }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query, size: 0, }), diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx index 8f42b4cf1bc6a..0e16a404cbd54 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx @@ -19,7 +19,7 @@ import { import { EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public'; -import { LOG_THRESHOLD_ALERT_TYPE_ID } from '@kbn/rule-data-utils'; +import { AlertConsumers, LOG_THRESHOLD_ALERT_TYPE_ID } from '@kbn/rule-data-utils'; import { rulesLocatorID, RulesParams } from '@kbn/observability-plugin/public'; import { EuiLink } from '@elastic/eui'; @@ -93,7 +93,8 @@ export const IndicesConfigurationPanel = React.memo<{ if (http) { const { ruleExecutionStatus } = await loadRuleAggregations({ http, - typesFilter: [LOG_THRESHOLD_ALERT_TYPE_ID], + ruleTypeIds: [LOG_THRESHOLD_ALERT_TYPE_ID], + consumers: [AlertConsumers.LOGS, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], }); const numberOfRules = Object.values(ruleExecutionStatus).reduce( (acc, value) => acc + value, diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx index a3926b95383d9..7b0ec7ed2d2f1 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx @@ -6,11 +6,16 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { AlertConsumers, ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils'; +import { + AlertConsumers, + INFRA_RULE_TYPE_IDS, + OBSERVABILITY_RULE_TYPE_IDS, +} from '@kbn/rule-data-utils'; import { BrushEndListener, type XYBrushEvent } from '@elastic/charts'; import { useSummaryTimeRange } from '@kbn/observability-plugin/public'; import { useBoolean } from '@kbn/react-hooks'; import type { TimeRange } from '@kbn/es-query'; +import { INFRA_ALERT_CONSUMERS } from '../../../../../../../common/constants'; import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; import { HeightRetainer } from '../../../../../../components/height_retainer'; import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; @@ -20,18 +25,18 @@ import { AlertsEsQuery } from '../../../../../../utils/filters/create_alerts_es_ import { ALERTS_PER_PAGE, ALERTS_TABLE_ID, - infraAlertFeatureIds, } from '../../../../../../components/shared/alerts/constants'; import AlertsStatusFilter from '../../../../../../components/shared/alerts/alerts_status_filter'; import { CreateAlertRuleButton } from '../../../../../../components/shared/alerts/links/create_alert_rule_button'; import { LinkToAlertsPage } from '../../../../../../components/shared/alerts/links/link_to_alerts_page'; -import { INFRA_ALERT_FEATURE_ID } from '../../../../../../../common/constants'; import { AlertFlyout } from '../../../../../../alerting/inventory/components/alert_flyout'; import { usePluginConfig } from '../../../../../../containers/plugin_config_context'; +import { useHostsViewContext } from '../../../hooks/use_hosts_view'; export const AlertsTabContent = () => { const { services } = useKibanaContextForPlugin(); const { featureFlags } = usePluginConfig(); + const { hostNodes } = useHostsViewContext(); const { alertStatus, setAlertStatus, alertsEsQueryByStatus } = useAlertsQuery(); const [isAlertFlyoutVisible, { toggle: toggleAlertFlyout }] = useBoolean(false); @@ -43,6 +48,11 @@ export const AlertsTabContent = () => { const { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable } = triggersActionsUi; + const hostsWithAlertsKuery = hostNodes + .filter((host) => host.alertsCount) + .map((host) => `"${host.name}"`) + .join(' OR '); + return ( @@ -63,7 +73,7 @@ export const AlertsTabContent = () => { @@ -80,7 +90,8 @@ export const AlertsTabContent = () => { { const { alertsEsQuery } = useAlertsQuery(); const { alertsCount, loading, error } = useAlertsCount({ - featureIds: infraAlertFeatureIds, + ruleTypeIds: INFRA_RULE_TYPE_IDS, + consumers: INFRA_ALERT_CONSUMERS, query: alertsEsQuery, }); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx index d42670f190fde..c2493df3a3968 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx @@ -145,6 +145,18 @@ export const NodesOverview = ({ currentTime={currentTime} onFilter={handleDrilldown} /> + {nodeType === assetType && detailsItemId && ( + + )} ); } diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/table_view.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/table_view.tsx index 182c74c124fd9..e41bf377e40e1 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/table_view.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/table_view.tsx @@ -17,6 +17,7 @@ import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../common/in import { fieldToName } from '../lib/field_to_display_name'; import { NodeContextMenu } from './waffle/node_context_menu'; import { SnapshotNode, SnapshotNodePath } from '../../../../../common/http_api/snapshot_api'; +import { useAssetDetailsFlyoutState } from '../hooks/use_asset_details_flyout_url_state'; interface Props { nodes: SnapshotNode[]; @@ -49,6 +50,16 @@ export const TableView = (props: Props) => { const { nodes, options, formatter, currentTime, nodeType } = props; const [openPopoverId, setOpenPopoverId] = useState(null); + const [_, setFlyoutUrlState] = useAssetDetailsFlyoutState(); + const isFlyoutMode = nodeType === 'host' || nodeType === 'container'; + + const toggleAssetPopover = (uniqueID: string, nodeId: string) => { + if (isFlyoutMode) { + setFlyoutUrlState({ detailsItemId: nodeId, assetType: nodeType }); + } else { + setOpenPopoverId(uniqueID); + } + }; const closePopover = () => setOpenPopoverId(null); @@ -69,14 +80,14 @@ export const TableView = (props: Props) => { setOpenPopoverId(uniqueID)} + onClick={() => toggleAssetPopover(uniqueID, item.node.id)} > {value} ); - return ( + return !isFlyoutMode ? ( { options={options} /> + ) : ( + button ); }, }, diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx index 8deaa805ba9b4..328ef4680680e 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx @@ -20,6 +20,7 @@ import { import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public'; import { HttpSetup } from '@kbn/core-http-browser'; import { + AlertConsumers, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID, } from '@kbn/rule-data-utils'; @@ -56,7 +57,12 @@ export const SourceConfigurationSettings = ({ if (http) { const { ruleExecutionStatus } = await loadRuleAggregations({ http, - typesFilter: [METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID], + ruleTypeIds: [METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID], + consumers: [ + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.ALERTS, + AlertConsumers.OBSERVABILITY, + ], }); const numberOfRules = Object.values(ruleExecutionStatus).reduce( (acc, value) => acc + value, diff --git a/x-pack/plugins/observability_solution/infra/public/test_utils/entries.ts b/x-pack/plugins/observability_solution/infra/public/test_utils/entries.ts index 0b04c90ee633d..7042a6538dceb 100644 --- a/x-pack/plugins/observability_solution/infra/public/test_utils/entries.ts +++ b/x-pack/plugins/observability_solution/infra/public/test_utils/entries.ts @@ -5,7 +5,7 @@ * 2.0. */ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { LogEntry, LogViewColumnConfiguration } from '@kbn/logs-shared-plugin/common'; export function generateFakeEntries( @@ -51,15 +51,15 @@ export function generateFakeEntries( function fakeColumnValue(field: string): string { switch (field) { case 'message': - return faker.fake( - '{{internet.ip}} - [{{date.past}}] "GET {{internet.url}} HTTP/1.1" 200 {{random.number}} "-" "{{internet.userAgent}}"' + return faker.helpers.fake( + '{{internet.ip}} - [{{date.past}}] "GET {{internet.url}} HTTP/1.1" 200 {{number.int}} "-" "{{internet.userAgent}}"' ); case 'event.dataset': - return faker.fake('{{hacker.noun}}.{{hacker.noun}}'); + return faker.helpers.fake('{{hacker.noun}}.{{hacker.noun}}'); case 'log.file.path': return faker.system.filePath(); case 'log.level': - return faker.random.arrayElement(['debug', 'info', 'warn', 'error']); + return faker.helpers.arrayElement(['debug', 'info', 'warn', 'error']); case 'host.name': return faker.hacker.noun(); default: diff --git a/x-pack/plugins/observability_solution/infra/server/features.ts b/x-pack/plugins/observability_solution/infra/server/features.ts index b2f83967920e1..77fb8d317fefd 100644 --- a/x-pack/plugins/observability_solution/infra/server/features.ts +++ b/x-pack/plugins/observability_solution/infra/server/features.ts @@ -14,6 +14,7 @@ import { } from '@kbn/rule-data-utils'; import { ES_QUERY_ID } from '@kbn/rule-data-utils'; import { metricsDataSourceSavedObjectName } from '@kbn/metrics-data-access-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '../common/alerting/logs/log_threshold/types'; import { @@ -31,6 +32,11 @@ const metricRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const metricAlertingFeatures = metricRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [METRICS_FEATURE_ID, ALERTING_FEATURE_ID], +})); + export const METRICS_FEATURE = { id: METRICS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkInfrastructureTitle', { @@ -44,7 +50,7 @@ export const METRICS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: metricRuleTypes, + alerting: metricAlertingFeatures, privileges: { all: { app: ['infra', 'metrics', 'kibana'], @@ -56,10 +62,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - all: metricRuleTypes, + all: metricAlertingFeatures, }, alert: { - all: metricRuleTypes, + all: metricAlertingFeatures, }, }, management: { @@ -77,10 +83,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - read: metricRuleTypes, + read: metricAlertingFeatures, }, alert: { - read: metricRuleTypes, + read: metricAlertingFeatures, }, }, management: { @@ -98,6 +104,11 @@ const logsRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const logsAlertingFeatures = logsRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [LOGS_FEATURE_ID, ALERTING_FEATURE_ID], +})); + export const LOGS_FEATURE = { id: LOGS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkLogsTitle', { @@ -111,7 +122,7 @@ export const LOGS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: logsRuleTypes, + alerting: logsAlertingFeatures, privileges: { all: { app: ['infra', 'logs', 'kibana', 'observability-logs-explorer'], @@ -123,10 +134,10 @@ export const LOGS_FEATURE = { }, alerting: { rule: { - all: logsRuleTypes, + all: logsAlertingFeatures, }, alert: { - all: logsRuleTypes, + all: logsAlertingFeatures, }, }, management: { @@ -140,10 +151,10 @@ export const LOGS_FEATURE = { api: ['infra', 'rac'], alerting: { rule: { - read: logsRuleTypes, + read: logsAlertingFeatures, }, alert: { - read: logsRuleTypes, + read: logsAlertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts index b8dd11a17fb0b..3ee4f9632b359 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts @@ -20,7 +20,7 @@ import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; import { RuleRegistryPluginSetupContract, @@ -46,7 +46,7 @@ import type { } from '@kbn/entityManager-plugin/server'; export interface InfraServerPluginSetupDeps { - alerting: AlertingPluginContract; + alerting: AlertingServerSetup; data: DataPluginSetup; home: HomeServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/adapters/source_status/elasticsearch_source_status_adapter.ts b/x-pack/plugins/observability_solution/infra/server/lib/adapters/source_status/elasticsearch_source_status_adapter.ts index 54e2831899482..ff8058011baea 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/adapters/source_status/elasticsearch_source_status_adapter.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/adapters/source_status/elasticsearch_source_status_adapter.ts @@ -5,11 +5,14 @@ * 2.0. */ +import type { DataTier } from '@kbn/observability-shared-plugin/common'; +import { searchExcludedDataTiers } from '@kbn/observability-plugin/common/ui_settings_keys'; +import { excludeTiersQuery } from '@kbn/observability-utils-common/es/queries/exclude_tiers_query'; import type { InfraPluginRequestHandlerContext } from '../../../types'; import { isNoSuchRemoteClusterMessage, NoSuchRemoteClusterError } from '../../sources/errors'; -import { InfraSourceStatusAdapter, SourceIndexStatus } from '../../source_status'; -import { InfraDatabaseGetIndicesResponse } from '../framework'; -import { KibanaFramework } from '../framework/kibana_framework_adapter'; +import type { InfraSourceStatusAdapter, SourceIndexStatus } from '../../source_status'; +import type { InfraDatabaseGetIndicesResponse } from '../framework'; +import type { KibanaFramework } from '../framework/kibana_framework_adapter'; export class InfraElasticsearchSourceStatusAdapter implements InfraSourceStatusAdapter { constructor(private readonly framework: KibanaFramework) {} @@ -46,6 +49,12 @@ export class InfraElasticsearchSourceStatusAdapter implements InfraSourceStatusA requestContext: InfraPluginRequestHandlerContext, indexNames: string ): Promise { + const { uiSettings } = await requestContext.core; + + const excludedDataTiers = await uiSettings.client.get(searchExcludedDataTiers); + + const filter = excludedDataTiers.length ? excludeTiersQuery(excludedDataTiers) : []; + return await this.framework .callWithRequest(requestContext, 'search', { ignore_unavailable: true, @@ -54,6 +63,7 @@ export class InfraElasticsearchSourceStatusAdapter implements InfraSourceStatusA size: 0, terminate_after: 1, track_total_hits: 1, + query: { bool: { filter } }, }) .then( (response) => { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts index 7b69d76ba0ce9..f85738248a9c0 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts @@ -8,7 +8,7 @@ import { schema, Type } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import { GetViewInAppRelativeUrlFnOpts, AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration'; import { @@ -81,7 +81,7 @@ const groupActionVariableDescription = i18n.translate( ); export function registerInventoryThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig, locators: InfraLocators diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts index decac47dbb5f9..d4eb9050499cf 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts @@ -7,7 +7,10 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { + GetViewInAppRelativeUrlFnOpts, + AlertingServerSetup, +} from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { decodeOrThrow } from '@kbn/io-ts-utils'; import type { InfraConfig } from '../../../../common/plugin_config_types'; @@ -103,7 +106,7 @@ const viewInAppUrlActionVariableDescription = i18n.translate( ); export function registerLogThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig ) { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 9777f7ceda476..4227ff10ad902 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -102,6 +102,7 @@ const mockOptions = { const date = STARTED_AT_MOCK_DATE.toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }; const setEvaluationResults = (response: Array>) => { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts index 6369465773cf7..3cc272a02c7fe 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts @@ -8,7 +8,10 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { + GetViewInAppRelativeUrlFnOpts, + AlertingServerSetup, +} from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator'; @@ -46,7 +49,7 @@ import { MetricsRulesTypeAlertDefinition } from '../register_rule_types'; import { O11Y_AAD_FIELDS } from '../../../../common/constants'; export function registerMetricThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig, locators: InfraLocators diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts index 125c3135a235d..6d06c2c98607e 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts @@ -6,7 +6,7 @@ */ import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; -import { type IRuleTypeAlerts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import { type IRuleTypeAlerts, AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { registerMetricThresholdRuleType } from './metric_threshold/register_metric_threshold_rule_type'; import { registerInventoryThresholdRuleType } from './inventory_metric_threshold/register_inventory_metric_threshold_rule_type'; import { registerLogThresholdRuleType } from './log_threshold/register_log_threshold_rule_type'; @@ -36,7 +36,7 @@ export const MetricsRulesTypeAlertDefinition: IRuleTypeAlerts { + const hasPrivileges = async () => { + const apmDataAccessStart = await libs.plugins.apmDataAccess.start(); + return apmDataAccessStart.hasPrivileges({ request }); + }; + const getServices = async () => { const apmDataAccess = libs.plugins.apmDataAccess.setup; const coreContext = await context.core; - const { uiSettings, elasticsearch } = coreContext; + const { savedObjects, uiSettings, elasticsearch } = coreContext; + const savedObjectsClient = savedObjects.client; const esClient = elasticsearch.client.asCurrentUser; const uiSettingsClient = uiSettings.client; const [apmIndices, includeFrozen] = await Promise.all([ - apmDataAccess.getApmIndices(), + apmDataAccess.getApmIndices(savedObjectsClient), uiSettingsClient.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), ]); @@ -80,5 +86,5 @@ export const getApmDataAccessClient = ({ }; }; - return { getServices }; + return { hasPrivileges, getServices }; }; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts index 58dfdde223ebd..99464efd02567 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import type { KibanaRequest } from '@kbn/core/server'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import type { InfraBackendLibs } from '../infra_types'; type RequiredParams = ESSearchRequest & { @@ -26,7 +27,9 @@ export async function getInfraAlertsClient({ }) { const [, { ruleRegistry }] = await libs.getStartServices(); const alertsClient = await ruleRegistry.getRacClientWithRequest(request); - const infraAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(['infrastructure']); + const infraAlertsIndices = await alertsClient.getAuthorizedAlertsIndices( + OBSERVABILITY_RULE_TYPE_IDS + ); if (!infraAlertsIndices || isEmpty(infraAlertsIndices)) { throw Error('No alert indices exist for "infrastructure"'); diff --git a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.test.ts b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.test.ts new file mode 100644 index 0000000000000..3eb8c47c274d9 --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaRequest } from '@kbn/core-http-server'; +import { DataTier } from '@kbn/observability-shared-plugin/common'; +import { InfraBackendLibs } from '../infra_types'; +import { getInfraMetricsClient } from './get_infra_metrics_client'; +import { InfraPluginRequestHandlerContext } from '../../types'; +import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; + +const withExcludedDataTiers = (tiers: DataTier[]) => ({ + uiSettings: { + client: { + get: () => Promise.resolve(tiers), + }, + }, +}); + +const mockedInfra = { getMetricsIndices: () => Promise.resolve(['*.indices']) }; + +const infraMetricsTestHarness = + (tiers: DataTier[], input: QueryDslQueryContainer | undefined, output: QueryDslQueryContainer) => + async () => { + const callWithRequest = jest.fn(); + + const mockedCore = withExcludedDataTiers(tiers); + + const context = { + infra: Promise.resolve(mockedInfra), + core: Promise.resolve(mockedCore), + } as unknown as InfraPluginRequestHandlerContext; + + const client = await getInfraMetricsClient({ + libs: { framework: { callWithRequest } } as unknown as InfraBackendLibs, + context, + request: {} as unknown as KibanaRequest, + }); + + await client.search({ + body: { + query: input, + size: 1, + track_total_hits: false, + }, + }); + + expect(callWithRequest).toBeCalledWith( + context, + 'search', + { + body: { + query: output, + size: 1, + track_total_hits: false, + }, + ignore_unavailable: true, + index: ['*.indices'], + }, + {} + ); + }; + +describe('getInfraMetricsClient', () => { + it( + 'defines an empty must_not query if given no data tiers to filter by', + infraMetricsTestHarness([], undefined, { bool: { must_not: [] } }) + ); + + it( + 'includes excluded data tiers in the request filter by default', + infraMetricsTestHarness(['data_frozen'], undefined, { + bool: { + must_not: [ + { + terms: { + _tier: ['data_frozen'], + }, + }, + ], + }, + }) + ); + + it( + 'merges provided filters with the excluded data tier filter', + infraMetricsTestHarness( + ['data_frozen'], + { + bool: { + must_not: { + exists: { + field: 'a-field', + }, + }, + }, + }, + { + bool: { + must_not: [ + { + exists: { + field: 'a-field', + }, + }, + { + terms: { + _tier: ['data_frozen'], + }, + }, + ], + }, + } + ) + ); + + it( + 'merges other query params with the excluded data tiers filter', + infraMetricsTestHarness( + ['data_frozen'], + { + bool: { + must: { + exists: { + field: 'a-field', + }, + }, + }, + }, + { + bool: { + must: { + exists: { + field: 'a-field', + }, + }, + must_not: [ + { + terms: { + _tier: ['data_frozen'], + }, + }, + ], + }, + } + ) + ); +}); diff --git a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.ts b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.ts index d560ffc358a5c..96ae89b902285 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_metrics_client.ts @@ -6,6 +6,10 @@ */ import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import type { KibanaRequest } from '@kbn/core/server'; +import { searchExcludedDataTiers } from '@kbn/observability-plugin/common/ui_settings_keys'; +import type { DataTier } from '@kbn/observability-shared-plugin/common'; +import { excludeTiersQuery } from '@kbn/observability-utils-common/es/queries/exclude_tiers_query'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import type { InfraPluginRequestHandlerContext } from '../../types'; import type { InfraBackendLibs } from '../infra_types'; @@ -29,12 +33,25 @@ export async function getInfraMetricsClient({ }) { const { framework } = libs; const infraContext = await context.infra; + const { uiSettings } = await context.core; + + const excludedDataTiers = await uiSettings.client.get(searchExcludedDataTiers); const metricsIndices = await infraContext.getMetricsIndices(); + const excludedQuery = excludedDataTiers.length + ? excludeTiersQuery(excludedDataTiers)[0].bool!.must_not! + : []; + return { search( searchParams: TParams ): Promise> { + const searchFilter = searchParams.body.query?.bool?.must_not ?? []; + + // This flattens arrays by one level, and non-array values can be added as well, so it all + // results in a nice [QueryDsl, QueryDsl, ...] array. + const mustNot = ([] as QueryDslQueryContainer[]).concat(searchFilter, excludedQuery); + return framework.callWithRequest( context, 'search', @@ -42,6 +59,16 @@ export async function getInfraMetricsClient({ ...searchParams, ignore_unavailable: true, index: metricsIndices, + body: { + ...searchParams.body, + query: { + ...searchParams.body.query, + bool: { + ...searchParams.body.query?.bool, + must_not: mustNot, + }, + }, + }, }, request ) as Promise; diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts index 3f91a034c8103..1b720eeb31869 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts @@ -41,11 +41,12 @@ export const initInfraAssetRoutes = (libs: InfraBackendLibs) => { try { const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); const [infraMetricsClient, alertsClient, apmDataAccessServices] = await Promise.all([ getInfraMetricsClient({ request, libs, context }), getInfraAlertsClient({ libs, request }), - apmDataAccessClient.getServices(), + hasApmPrivileges ? apmDataAccessClient.getServices() : undefined, ]); const hosts = await getHosts({ @@ -96,10 +97,11 @@ export const initInfraAssetRoutes = (libs: InfraBackendLibs) => { try { const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); const [infraMetricsClient, apmDataAccessServices] = await Promise.all([ getInfraMetricsClient({ request, libs, context }), - apmDataAccessClient.getServices(), + hasApmPrivileges ? apmDataAccessClient.getServices() : undefined, ]); const count = await getHostsCount({ diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts index 52da69cd7c008..570c1499f3b74 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts @@ -9,7 +9,6 @@ import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; import { termQuery } from '@kbn/observability-plugin/server'; import { ApmDocumentType, type TimeRangeMetadata } from '@kbn/apm-data-access-plugin/common'; import { estypes } from '@elastic/elasticsearch'; -import { castArray } from 'lodash'; import type { ApmDataAccessServicesWrapper } from '../../../../lib/helpers/get_apm_data_access_client'; import { EVENT_MODULE, @@ -18,16 +17,12 @@ import { } from '../../../../../common/constants'; import type { InfraAssetMetricType } from '../../../../../common/http_api/infra'; -export const getFilterByIntegration = ( - integration: typeof SYSTEM_INTEGRATION, - extraFilter: estypes.QueryDslQueryContainer[] = [] -) => { +export const getFilterByIntegration = (integration: typeof SYSTEM_INTEGRATION) => { return { bool: { should: [ ...termQuery(EVENT_MODULE, integration), ...termQuery(METRICSET_MODULE, integration), - ...extraFilter, ], minimum_should_match: 1, }, @@ -68,6 +63,7 @@ export const getDocumentsFilter = async ({ from: number; to: number; }) => { + const filters: estypes.QueryDslQueryContainer[] = [getFilterByIntegration('system')]; const apmDocumentsFilter = apmDataAccessServices && apmDocumentSources ? await getApmDocumentsFilter({ @@ -78,9 +74,9 @@ export const getDocumentsFilter = async ({ }) : undefined; - const filters: estypes.QueryDslQueryContainer[] = [ - getFilterByIntegration('system', apmDocumentsFilter && castArray(apmDocumentsFilter)), - ]; + if (apmDocumentsFilter) { + filters.push(apmDocumentsFilter); + } return filters; }; diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts index 63fef5d438b00..bb5bd51cfe1f9 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts @@ -49,7 +49,6 @@ export const getHosts = async ({ const [hostMetricsResponse, alertsCountResponse] = await Promise.all([ getAllHosts({ infraMetricsClient, - apmDataAccessServices, apmDocumentSources, from, to, diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts index c3d8f0f674d55..dbb1a3c2ceb69 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts @@ -6,14 +6,13 @@ */ import { termQuery, termsQuery } from '@kbn/observability-plugin/server'; -import { observabilityFeatureId } from '@kbn/observability-shared-plugin/common'; import { ALERT_RULE_PRODUCER, ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_UUID, } from '@kbn/rule-data-utils'; -import { HOST_NAME_FIELD, INFRA_ALERT_FEATURE_ID } from '../../../../../common/constants'; +import { HOST_NAME_FIELD, INFRA_ALERT_CONSUMERS } from '../../../../../common/constants'; import { GetHostParameters } from '../types'; export async function getHostsAlertsCount({ @@ -41,7 +40,7 @@ export async function getHostsAlertsCount({ query: { bool: { filter: [ - ...termsQuery(ALERT_RULE_PRODUCER, INFRA_ALERT_FEATURE_ID, observabilityFeatureId), + ...termsQuery(ALERT_RULE_PRODUCER, ...INFRA_ALERT_CONSUMERS), ...termQuery(ALERT_STATUS, ALERT_STATUS_ACTIVE), ...termsQuery(HOST_NAME_FIELD, ...hostNames), ...rangeQuery, diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts index e36811ea5b87a..154fd8796520d 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts @@ -25,14 +25,8 @@ export async function getHostsCount({ }) { assertQueryStructure(query); - const apmDocumentSources = await apmDataAccessServices?.getDocumentSources({ - start: from, - end: to, - }); - const documentsFilter = await getDocumentsFilter({ apmDataAccessServices, - apmDocumentSources, from, to, }); @@ -45,7 +39,7 @@ export async function getHostsCount({ query: { bool: { filter: [query, ...rangeQuery(from, to)], - must: [...documentsFilter], + should: [...documentsFilter], }, }, aggs: { diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts index 8f50d9eb89f13..87679f24271d6 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts @@ -13,5 +13,5 @@ import { InfraMetricsClient } from '../../../lib/helpers/get_infra_metrics_clien export interface GetHostParameters extends GetInfraMetricsRequestBodyPayload { infraMetricsClient: InfraMetricsClient; alertsClient: InfraAlertsClient; - apmDataAccessServices: ApmDataAccessServicesWrapper; + apmDataAccessServices?: ApmDataAccessServicesWrapper; } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/metrics_sources/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/metrics_sources/index.ts index 20dcbc1b7e20b..77bdee365e3bf 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/metrics_sources/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/metrics_sources/index.ts @@ -208,7 +208,7 @@ export const initMetricsSourceConfigurationRoutes = (libs: InfraBackendLibs) => }, async (context, request, response) => { try { - const modules = castArray(request.query.modules); + const modules = request.query.modules ? castArray(request.query.modules) : []; if (modules.length > MAX_MODULES) { throw Boom.badRequest( diff --git a/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts index bc6ce91e830ad..9673b31788487 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts @@ -36,6 +36,16 @@ export const initServicesRoute = (libs: InfraBackendLibs) => { const { from, to, size = 10, validatedFilters } = request.query; const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); + + if (!hasApmPrivileges) { + return response.customError({ + statusCode: 403, + body: { + message: 'APM data access service is not available', + }, + }); + } const apmDataAccessServices = await apmDataAccessClient.getServices(); diff --git a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts index 68ae0bd95b410..ee2d5967b081b 100644 --- a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts +++ b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IRuleDataClient, RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; export interface RulesServiceSetupDeps { - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; } diff --git a/x-pack/plugins/observability_solution/infra/tsconfig.json b/x-pack/plugins/observability_solution/infra/tsconfig.json index efd8be77b688c..1e130261d5346 100644 --- a/x-pack/plugins/observability_solution/infra/tsconfig.json +++ b/x-pack/plugins/observability_solution/infra/tsconfig.json @@ -116,7 +116,8 @@ "@kbn/entityManager-plugin", "@kbn/entities-schema", "@kbn/zod", - "@kbn/observability-utils-server" + "@kbn/observability-utils-server", + "@kbn/observability-utils-common" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index 65fd8a4ffbd7a..b006fa0c7f6d8 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -5,8 +5,6 @@ * 2.0. */ import { ENTITY_LATEST, entitiesAliasPattern, type EntityMetadata } from '@kbn/entities-schema'; -import { decode, encode } from '@kbn/rison'; -import { isRight } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; export const entityColumnIdsRt = t.union([ @@ -19,49 +17,6 @@ export const entityColumnIdsRt = t.union([ export type EntityColumnIds = t.TypeOf; -export const entityViewRt = t.union([t.literal('unified'), t.literal('grouped')]); - -const paginationRt = t.record(t.string, t.number); -export const entityPaginationRt = new t.Type | undefined, string, unknown>( - 'entityPaginationRt', - paginationRt.is, - (input, context) => { - switch (typeof input) { - case 'string': { - try { - const decoded = decode(input); - const validation = paginationRt.decode(decoded); - if (isRight(validation)) { - return t.success(validation.right); - } - - return t.failure(input, context); - } catch (e) { - return t.failure(input, context); - } - } - - case 'undefined': - return t.success(input); - - default: { - const validation = paginationRt.decode(input); - - if (isRight(validation)) { - return t.success(validation.right); - } - - return t.failure(input, context); - } - } - }, - (o) => encode(o) -); - -export type EntityView = t.TypeOf; - -export type EntityPagination = t.TypeOf; - export const defaultEntitySortField: EntityColumnIds = 'alertsCount'; export const MAX_NUMBER_OF_ENTITIES = 500; diff --git a/x-pack/plugins/observability_solution/inventory/common/rt_types.ts b/x-pack/plugins/observability_solution/inventory/common/rt_types.ts new file mode 100644 index 0000000000000..17496d672e610 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/rt_types.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { decode, encode } from '@kbn/rison'; +import { isRight } from 'fp-ts/lib/Either'; +import * as t from 'io-ts'; + +const validate = (validationRt: t.Any) => (input: unknown, context: t.Context) => { + switch (typeof input) { + case 'string': { + try { + const decoded = decode(input); + const validation = validationRt.decode(decoded); + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } catch (e) { + return t.failure(input, context); + } + } + + case 'undefined': + return t.success(input); + + default: { + const validation = validationRt.decode(input); + + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } + } +}; + +const entityTypeCheckOptions = t.union([t.literal('on'), t.literal('off'), t.literal('mixed')]); +export type EntityTypeCheckOptions = t.TypeOf; + +const entityTypeRt = t.record(t.string, entityTypeCheckOptions); +export type EntityType = t.TypeOf; +export const entityTypesRt = new t.Type< + Record | undefined, + string, + unknown +>('entityTypesRt', entityTypeRt.is, validate(entityTypeRt), (o) => encode(o)); + +const paginationRt = t.record(t.string, t.number); +export type EntityPagination = t.TypeOf; +export const entityPaginationRt = new t.Type | undefined, string, unknown>( + 'entityPaginationRt', + paginationRt.is, + validate(paginationRt), + (o) => encode(o) +); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts index fdb68826e9dc8..c2e7f1232e6aa 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts @@ -80,25 +80,6 @@ describe('Home page', () => { cy.contains('foo'); }); - it('Shows inventory page with unified view of entities', () => { - cy.intercept('GET', '/internal/entities/managed/enablement', { - fixture: 'eem_enabled.json', - }).as('getEEMStatus'); - cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); - cy.visitKibana('/app/inventory'); - cy.wait('@getEEMStatus'); - cy.contains('Group entities by: Type'); - cy.getByTestSubj('groupSelectorDropdown').click(); - cy.getByTestSubj('panelUnified').click(); - cy.wait('@getEntities'); - cy.contains('server1'); - cy.contains('host'); - cy.contains('synth-node-trace-logs'); - cy.contains('service'); - cy.contains('foo'); - cy.contains('container'); - }); - it('Navigates to apm when clicking on a service type entity', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', @@ -148,85 +129,85 @@ describe('Home page', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-service').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_service').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_service').click(); cy.wait('@getEntities'); cy.get('server1').should('not.exist'); cy.contains('synth-node-trace-logs'); cy.contains('foo').should('not.exist'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_service').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_service').should('not.exist'); }); it('Filters entities by host type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-host').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_host').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_host').click(); cy.wait('@getEntities'); cy.contains('server1'); cy.contains('synth-node-trace-logs').should('not.exist'); cy.contains('foo').should('not.exist'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_host').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_host').should('not.exist'); }); it('Filters entities by container type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-container').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_container').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); cy.wait('@getEntities'); cy.contains('server1').should('not.exist'); cy.contains('synth-node-trace-logs').should('not.exist'); cy.contains('foo'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_container').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_container').should('not.exist'); }); it('Navigates to discover with actions button in the entities list', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.contains('container'); cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); + cy.wait('@getEntities'); + // cy.getByTestSubj('inventoryEntityActionsButton').click(); cy.getByTestSubj('inventoryEntityActionsButton-foo').click(); - cy.getByTestSubj('inventoryEntityActionOpenInDiscover').click(); - cy.url().should( - 'include', - "query:'container.id:%20%22foo%22%20AND%20entity.definition_id%20:%20builtin*" - ); + cy.getByTestSubj('inventoryEntityActionExploreInDiscover').click(); + cy.url().should('include', "query:'container.id:%20%22foo%22"); }); }); }); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts index 6694b50ce9c70..c3462f8b6ff18 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts @@ -27,23 +27,31 @@ Cypress.Commands.add('loginAsSuperUser', () => { Cypress.Commands.add( 'loginAs', ({ username, password }: { username: string; password: string }) => { - const kibanaUrl = Cypress.env('KIBANA_URL'); - cy.log(`Logging in as ${username} on ${kibanaUrl}`); - cy.visit('/'); - cy.request({ - log: true, - method: 'POST', - url: `${kibanaUrl}/internal/security/login`, - body: { - providerType: 'basic', - providerName: 'basic', - currentURL: `${kibanaUrl}/login`, - params: { username, password }, + cy.session( + username, + () => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + cy.log(`Logging in as ${username} on ${kibanaUrl}`); + cy.visit('/'); + cy.request({ + log: true, + method: 'POST', + url: `${kibanaUrl}/internal/security/login`, + body: { + providerType: 'basic', + providerName: 'basic', + currentURL: `${kibanaUrl}/login`, + params: { username, password }, + }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + }); + cy.visit('/'); }, - headers: { - 'kbn-xsrf': 'e2e_test', - }, - }); - cy.visit('/'); + { + cacheAcrossSpecs: true, + } + ); } ); diff --git a/x-pack/plugins/observability_solution/inventory/kibana.jsonc b/x-pack/plugins/observability_solution/inventory/kibana.jsonc index e6e7c5f2fa2f8..e7cc398c9c655 100644 --- a/x-pack/plugins/observability_solution/inventory/kibana.jsonc +++ b/x-pack/plugins/observability_solution/inventory/kibana.jsonc @@ -21,7 +21,7 @@ "ruleRegistry", "share" ], - "requiredBundles": ["kibanaReact","controls"], + "requiredBundles": ["kibanaReact"], "optionalPlugins": ["spaces", "cloud"], "extraPublicDirs": [] } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx index 5195a35b93f4e..1892dd0109490 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx @@ -15,12 +15,10 @@ const useKibanaMock = useKibana as jest.Mock; const commonEntityFields: Partial = { entityLastSeenTimestamp: 'foo', - entityId: '1', + entityId: 'entity1', }; describe('AlertsBadge', () => { - const mockAsKqlFilter = jest.fn(); - beforeEach(() => { jest.clearAllMocks(); @@ -31,11 +29,6 @@ describe('AlertsBadge', () => { prepend: (path: string) => path, }, }, - entityManager: { - entityClient: { - asKqlFilter: mockAsKqlFilter, - }, - }, }, }); }); @@ -59,11 +52,10 @@ describe('AlertsBadge', () => { provider: null, }, }; - mockAsKqlFilter.mockReturnValue('host.name: foo'); render(); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'host.name: foo',status:active)" + `/app/observability/alerts?_a=(kuery:\"entity1\",status:active)` ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('1'); }); @@ -86,40 +78,11 @@ describe('AlertsBadge', () => { alertsCount: 5, }; - mockAsKqlFilter.mockReturnValue('service.name: bar'); render(); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'service.name: bar',status:active)" + `/app/observability/alerts?_a=(kuery:\"entity1\",status:active)` ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('5'); }); - it('render alerts badge for a service entity with multiple identity fields', () => { - const entity: InventoryEntity = { - ...(commonEntityFields as InventoryEntity), - entityType: 'service', - entityDisplayName: 'foo', - entityIdentityFields: ['service.name', 'service.environment'], - entityDefinitionId: 'service', - service: { - name: 'bar', - environment: 'prod', - }, - agent: { - name: 'node', - }, - cloud: { - provider: null, - }, - alertsCount: 2, - }; - - mockAsKqlFilter.mockReturnValue('service.name: bar AND service.environment: prod'); - - render(); - expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'service.name: bar AND service.environment: prod',status:active)" - ); - expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('2'); - }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx index ed873bdb68c21..228cd3d8bbfd8 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx @@ -15,21 +15,16 @@ export function AlertsBadge({ entity }: { entity: InventoryEntity }) { const { services: { http: { basePath }, - entityManager, }, } = useKibana(); const activeAlertsHref = basePath.prepend( `/app/observability/alerts?_a=${rison.encode({ - kuery: entityManager.entityClient.asKqlFilter({ - entity: { - identity_fields: entity.entityIdentityFields, - }, - ...entity, - }), + kuery: `"${entity.entityId}"`, status: 'active', })}` ); + return ( { }); it('opens the popover when the badge is clicked', () => { - render(); + render(); expect(screen.queryByTestId(popoverContentDataTestId)).not.toBeInTheDocument(); fireEvent.click(screen.getByText(value)); expect(screen.queryByTestId(popoverContentDataTestId)).toBeInTheDocument(); @@ -35,9 +35,25 @@ describe('BadgeFilterWithPopover', () => { }); it('copies value to clipboard when the "Copy value" button is clicked', () => { - render(); + render(); fireEvent.click(screen.getByText(value)); fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverCopyValueButton')); expect(copyToClipboard).toHaveBeenCalledWith(value); }); + + it('Filter for an entity', () => { + const handleFilter = jest.fn(); + render(); + fireEvent.click(screen.getByText(value)); + fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverFilterForButton')); + expect(handleFilter).toHaveBeenCalledWith(value, 'on'); + }); + + it('Filter out an entity', () => { + const handleFilter = jest.fn(); + render(); + fireEvent.click(screen.getByText(value)); + fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverFilterOutButton')); + expect(handleFilter).toHaveBeenCalledWith(value, 'off'); + }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx index 83e0bb02e6d8d..ea85754dcbf75 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx @@ -18,19 +18,18 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import React, { useState } from 'react'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; +import type { EntityTypeCheckOptions } from '../../../common/rt_types'; interface Props { field: string; value: string; + onFilter: (value: string, checked: EntityTypeCheckOptions) => void; } -export function BadgeFilterWithPopover({ field, value }: Props) { +export function BadgeFilterWithPopover({ field, value, onFilter }: Props) { const [isOpen, setIsOpen] = useState(false); const theme = useEuiTheme(); - const { addFilter } = useUnifiedSearchContext(); return ( { - addFilter({ fieldName: ENTITY_TYPE, operation: '+', value }); + onFilter(value, 'on'); }} > {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', { @@ -92,10 +91,10 @@ export function BadgeFilterWithPopover({ field, value }: Props) { { - addFilter({ fieldName: ENTITY_TYPE, operation: '-', value }); + onFilter(value, 'off'); }} > {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx index ae80bf09ecae2..b5e9287a836dd 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx @@ -77,6 +77,7 @@ export const Grid: Story = (args) => { onChangePage={setPageIndex} onChangeSort={setSort} pageIndex={pageIndex} + onFilterByType={() => {}} /> @@ -99,6 +100,7 @@ export const EmptyGrid: Story = (args) => { onChangePage={setPageIndex} onChangeSort={setSort} pageIndex={pageIndex} + onFilterByType={() => {}} /> ); }; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx index dd421d30a3a9c..b26676494833e 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx @@ -14,7 +14,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'; import { last } from 'lodash'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import { EntityColumnIds, InventoryEntity } from '../../../common/entities'; import { BadgeFilterWithPopover } from '../badge_filter_with_popover'; @@ -22,7 +22,7 @@ import { getColumns } from './grid_columns'; import { AlertsBadge } from '../alerts_badge/alerts_badge'; import { EntityName } from './entity_name'; import { EntityActions } from '../entity_actions'; -import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; +import { type EntityTypeCheckOptions } from '../../../common/rt_types'; interface Props { loading: boolean; @@ -32,6 +32,7 @@ interface Props { pageIndex: number; onChangeSort: (sorting: EuiDataGridSorting['columns'][0]) => void; onChangePage: (nextPage: number) => void; + onFilterByType: (value: string, checked: EntityTypeCheckOptions) => void; } const PAGE_SIZE = 20; @@ -44,8 +45,9 @@ export function EntitiesGrid({ pageIndex, onChangePage, onChangeSort, + onFilterByType, }: Props) { - const { getDiscoverRedirectUrl } = useDiscoverRedirect(); + const [showActions, setShowActions] = useState(true); const onSort: EuiDataGridSorting['onSort'] = useCallback( (newSortingColumns) => { @@ -62,8 +64,6 @@ export function EntitiesGrid({ [entities] ); - const showActions = useMemo(() => !!getDiscoverRedirectUrl(), [getDiscoverRedirectUrl]); - const columnVisibility = useMemo( () => ({ visibleColumns: getColumns({ showAlertsColumn, showActions }).map(({ id }) => id), @@ -81,14 +81,19 @@ export function EntitiesGrid({ const columnEntityTableId = columnId as EntityColumnIds; const entityType = entity.entityType; - const discoverUrl = getDiscoverRedirectUrl(entity); switch (columnEntityTableId) { case 'alertsCount': return entity?.alertsCount ? : null; case 'entityType': - return ; + return ( + + ); case 'entityLastSeenTimestamp': return ( @@ -119,19 +124,12 @@ export function EntitiesGrid({ case 'entityDisplayName': return ; case 'actions': - return ( - discoverUrl && ( - - ) - ); + return ; default: return null; } }, - [entities, getDiscoverRedirectUrl] + [entities, onFilterByType] ); if (loading) { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx similarity index 72% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx index 63583e60b0edd..9f4a5df76e0d9 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx @@ -9,12 +9,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { EuiThemeProvider } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; -import { InventorySummary } from './inventory_summary'; - -// Do not test the GroupSelector, as it needs a lot more complicated setup -jest.mock('./group_selector', () => ({ - GroupSelector: () => <>Selector, -})); +import { EntitiesSummary } from '.'; function MockEnvWrapper({ children }: { children?: React.ReactNode }) { return ( @@ -24,19 +19,19 @@ function MockEnvWrapper({ children }: { children?: React.ReactNode }) { ); } -describe('InventorySummary', () => { +describe('EntitiesSummary', () => { it('renders the total entities without any group totals', () => { - render(, { wrapper: MockEnvWrapper }); + render(, { wrapper: MockEnvWrapper }); expect(screen.getByText('10 Entities')).toBeInTheDocument(); expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); }); it('renders the total entities with group totals', () => { - render(, { wrapper: MockEnvWrapper }); + render(, { wrapper: MockEnvWrapper }); expect(screen.getByText('15 Entities')).toBeInTheDocument(); expect(screen.queryByText('3 Groups')).toBeInTheDocument(); }); it("won't render either totals when not provided anything", () => { - render(, { wrapper: MockEnvWrapper }); + render(, { wrapper: MockEnvWrapper }); expect(screen.queryByTestId('inventorySummaryEntitiesTotal')).not.toBeInTheDocument(); expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx new file mode 100644 index 0000000000000..8388ad64407ac --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export function EntitiesSummary({ + totalEntities, + totalGroups, +}: { + totalEntities?: number; + totalGroups?: number; +}) { + const { euiTheme } = useEuiTheme(); + + const isGrouped = totalGroups !== undefined; + + return ( + + {totalEntities !== undefined && ( + + + + + + )} + {isGrouped ? ( + + + + + + ) : null} + + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx index 95a4050fba4e9..691ba4388ac63 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx @@ -7,56 +7,70 @@ import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { type SetStateAction } from 'react'; import { useBoolean } from '@kbn/react-hooks'; +import type { Dispatch } from '@kbn/kibana-utils-plugin/common'; +import type { InventoryEntity } from '../../../common/entities'; +import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; interface Props { - discoverUrl: string; - entityIdentifyingValue?: string; + entity: InventoryEntity; + setShowActions: Dispatch>; } -export const EntityActions = ({ discoverUrl, entityIdentifyingValue }: Props) => { +export const EntityActions = ({ entity, setShowActions }: Props) => { const [isPopoverOpen, { toggle: togglePopover, off: closePopover }] = useBoolean(false); - const actionButtonTestSubject = entityIdentifyingValue - ? `inventoryEntityActionsButton-${entityIdentifyingValue}` + const actionButtonTestSubject = entity.entityDisplayName + ? `inventoryEntityActionsButton-${entity.entityDisplayName}` : 'inventoryEntityActionsButton'; - const actions = [ - - {i18n.translate('xpack.inventory.entityActions.discoverLink', { - defaultMessage: 'Open in discover', - })} - , - ]; + const { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading } = useDiscoverRedirect(entity); + const discoverUrl = getDiscoverEntitiesRedirectUrl(); - return ( - <> - - } - closePopover={closePopover} + const actions: React.ReactElement[] = []; + + if (!discoverUrl && !isEntityDefinitionLoading) { + setShowActions(false); + return null; + } + + if (!isEntityDefinitionLoading) { + actions.push( + - - - + {i18n.translate('xpack.inventory.entityActions.exploreInDiscoverLink', { + defaultMessage: 'Explore in Discover', + })} + + ); + } + + return ( + + } + closePopover={closePopover} + > + + ); }; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx similarity index 95% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx index 43db1c39154bc..a0c9a2a18c4a6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx @@ -7,7 +7,7 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import React from 'react'; -export function InventoryPanelBadge({ +export function EntityCountBadge({ name, value, 'data-test-subj': dataTestSubj, diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx similarity index 80% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx index bf0b7064033f4..747124808df2e 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx @@ -7,10 +7,9 @@ import React from 'react'; import { render, screen, within } from '@testing-library/react'; +import { EntityGroupAccordion } from '.'; -import { InventoryGroupAccordion } from './inventory_group_accordion'; - -describe('Grouped Inventory Accordion', () => { +describe('EntityGroupAccordion', () => { it('renders with correct values', () => { const props = { groupBy: 'entity.type', @@ -26,14 +25,14 @@ describe('Grouped Inventory Accordion', () => { ], }; render( - ); expect(screen.getByText(props.groups[0]['entity.type'])).toBeInTheDocument(); - const container = screen.getByTestId('inventoryPanelBadgeEntitiesCount_entity.type_host'); + const container = screen.getByTestId('entityCountBadge_entity.type_host'); expect(within(container).getByText('Entities:')).toBeInTheDocument(); expect(within(container).getByText(props.groups[0].count)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx similarity index 67% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx index 911e997401023..5dde32cbb4aac 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx @@ -5,15 +5,16 @@ * 2.0. */ import { EuiDataGridSorting } from '@elastic/eui'; -import { decodeOrThrow } from '@kbn/io-ts-utils'; import React from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { type EntityColumnIds } from '../../../common/entities'; import { + type EntityTypeCheckOptions, entityPaginationRt, - type EntityColumnIds, - type EntityPagination, -} from '../../../common/entities'; + entityTypesRt, +} from '../../../common/rt_types'; import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; import { useInventoryParams } from '../../hooks/use_inventory_params'; import { useInventoryRouter } from '../../hooks/use_inventory_router'; import { useKibana } from '../../hooks/use_kibana'; @@ -24,29 +25,14 @@ interface Props { groupValue: string; } -const paginationDecoder = decodeOrThrow(entityPaginationRt); - export function GroupedEntitiesGrid({ groupValue }: Props) { const { query } = useInventoryParams('/'); - const { sortField, sortDirection, pagination: paginationQuery } = query; + const { sortField, sortDirection, kuery } = query; + const { pagination, entityTypes } = useInventoryDecodedQueryParams(); const inventoryRoute = useInventoryRouter(); - let pagination: EntityPagination | undefined = {}; - const { stringifiedEsQuery } = useUnifiedSearchContext(); - try { - pagination = paginationDecoder(paginationQuery); - } catch (error) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: undefined, - }, - }); - window.location.reload(); - } const pageIndex = pagination?.[groupValue] ?? 0; - const { refreshSubject$, isControlPanelsInitiated } = useUnifiedSearchContext(); + const { refreshSubject$ } = useUnifiedSearchContext(); const { services: { inventoryAPIClient }, } = useKibana(); @@ -57,28 +43,19 @@ export function GroupedEntitiesGrid({ groupValue }: Props) { refresh, } = useInventoryAbortableAsync( ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - params: { - query: { - sortDirection, - sortField, - esQuery: stringifiedEsQuery, - entityTypes: groupValue?.length ? JSON.stringify([groupValue]) : undefined, - }, + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + params: { + query: { + sortDirection, + sortField, + kuery, + entityTypes: groupValue?.length ? JSON.stringify([groupValue]) : undefined, }, - signal, - }); - } + }, + signal, + }); }, - [ - groupValue, - inventoryAPIClient, - sortDirection, - sortField, - isControlPanelsInitiated, - stringifiedEsQuery, - ] + [groupValue, inventoryAPIClient, sortDirection, sortField, kuery] ); useEffectOnce(() => { @@ -111,6 +88,16 @@ export function GroupedEntitiesGrid({ groupValue }: Props) { }); } + function handleEntityTypeFilter(entityType: string, checkOption: EntityTypeCheckOptions) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + entityTypes: entityTypesRt.encode({ ...entityTypes, [entityType]: checkOption }), + }, + }); + } + return ( ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx similarity index 85% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx index 0b4e9a46d4288..fa365625474b0 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx @@ -8,27 +8,22 @@ import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, useEuiTheme } from '@elast import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React, { useCallback, useState } from 'react'; +import { EntityCountBadge } from './entity_count_badge'; import { GroupedEntitiesGrid } from './grouped_entities_grid'; -import { InventoryPanelBadge } from './inventory_panel_badge'; const ENTITIES_COUNT_BADGE = i18n.translate( 'xpack.inventory.inventoryGroupPanel.entitiesBadgeLabel', { defaultMessage: 'Entities' } ); -export interface InventoryGroupAccordionProps { +export interface Props { groupBy: string; groupValue: string; groupCount: number; isLoading?: boolean; } -export function InventoryGroupAccordion({ - groupBy, - groupValue, - groupCount, - isLoading, -}: InventoryGroupAccordionProps) { +export function EntityGroupAccordion({ groupBy, groupValue, groupCount, isLoading }: Props) { const { euiTheme } = useEuiTheme(); const [open, setOpen] = useState(false); @@ -55,8 +50,8 @@ export function InventoryGroupAccordion({ } buttonElement="div" extraAction={ - diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/mock/inventory_component_wrapper_mock.tsx similarity index 100% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/mock/inventory_component_wrapper_mock.tsx diff --git a/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx new file mode 100644 index 0000000000000..6f504715e99c8 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx @@ -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 { render, screen } from '@testing-library/react'; +import React from 'react'; +import { GroupBySelector } from '.'; +import { InventoryComponentWrapperMock } from '../entity_group_accordion/mock/inventory_component_wrapper_mock'; + +describe('GroupBySelector', () => { + beforeEach(() => { + render( + + + + ); + }); + it('Should default to Type', async () => { + expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx similarity index 50% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx index 95264f3c81303..b9aa28d3f2980 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx @@ -5,49 +5,17 @@ * 2.0. */ -import { EuiPopover, EuiContextMenu, EuiButtonEmpty } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; +import { EuiButtonEmpty, EuiContextMenu, EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { EntityView } from '../../../common/entities'; -import { useInventoryParams } from '../../hooks/use_inventory_params'; -import { useInventoryRouter } from '../../hooks/use_inventory_router'; +import React, { useCallback, useState } from 'react'; -const GROUP_LABELS: Record = { - unified: i18n.translate('xpack.inventory.groupedInventoryPage.noneLabel', { - defaultMessage: 'None', - }), - grouped: i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { - defaultMessage: 'Type', - }), -}; +const ENTITY_TYPE_LABEL = i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { + defaultMessage: 'Type', +}); -export interface GroupedSelectorProps { - groupSelected: string; - onGroupChange: (groupSelection: string) => void; -} - -export function GroupSelector() { - const { query } = useInventoryParams('/'); - const inventoryRoute = useInventoryRouter(); +export function GroupBySelector() { const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const groupBy = query.view ?? 'grouped'; - - const onGroupChange = (selected: EntityView) => { - const { pagination: _, ...rest } = query; - - inventoryRoute.push('/', { - path: {}, - query: { - ...rest, - view: groupBy === selected ? 'unified' : selected, - }, - }); - }; - - const isGroupSelected = (groupKey: EntityView) => { - return groupBy === groupKey; - }; const panels = [ { @@ -56,17 +24,10 @@ export function GroupSelector() { defaultMessage: 'Select grouping', }), items: [ - { - 'data-test-subj': 'panelUnified', - name: GROUP_LABELS.unified, - icon: isGroupSelected('unified') ? 'check' : 'empty', - onClick: () => onGroupChange('unified'), - }, { 'data-test-subj': 'panelType', - name: GROUP_LABELS.grouped, - icon: isGroupSelected('grouped') ? 'check' : 'empty', - onClick: () => onGroupChange('grouped'), + name: ENTITY_TYPE_LABEL, + icon: 'check', }, ], }, @@ -83,13 +44,13 @@ export function GroupSelector() { iconSize="s" iconType="arrowDown" onClick={onButtonClick} - title={GROUP_LABELS[groupBy]} + title={ENTITY_TYPE_LABEL} size="s" > ); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx deleted file mode 100644 index 23cbb5b43c43b..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - -import { GroupSelector } from './group_selector'; - -import { InventoryComponentWrapperMock } from './mock/inventory_component_wrapper_mock'; - -describe('GroupSelector', () => { - beforeEach(() => { - render( - - - - ); - }); - it('Should default to Type', async () => { - expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); - }); - - it.skip('Should change to None', async () => { - const user = userEvent.setup(); - - const selector = screen.getByText('Group entities by: Type'); - - expect(selector).toBeInTheDocument(); - - await user.click(selector); - - const noneOption = screen.getByTestId('panelUnified'); - - expect(noneOption).toBeInTheDocument(); - - await user.click(noneOption); - - expect(await screen.findByText('Group entities by: None')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx deleted file mode 100644 index 6cfdc079be299..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { EuiSpacer } from '@elastic/eui'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; -import React from 'react'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { flattenObject } from '@kbn/observability-utils-common/object/flatten_object'; -import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; -import { useKibana } from '../../hooks/use_kibana'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; -import { InventoryGroupAccordion } from './inventory_group_accordion'; -import { InventorySummary } from './inventory_summary'; - -export function GroupedInventory() { - const { - services: { inventoryAPIClient }, - } = useKibana(); - const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } = - useUnifiedSearchContext(); - - const { - value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 }, - refresh, - loading, - } = useInventoryAbortableAsync( - ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', { - params: { - path: { - field: ENTITY_TYPE, - }, - query: { esQuery: stringifiedEsQuery }, - }, - signal, - }); - } - }, - [inventoryAPIClient, stringifiedEsQuery, isControlPanelsInitiated] - ); - - useEffectOnce(() => { - const refreshSubscription = refreshSubject$.subscribe(refresh); - - return () => refreshSubscription.unsubscribe(); - }); - - return ( - <> - - - {value.groups.map((group) => { - const groupValue = flattenObject(group)[value.groupBy]; - return ( - - ); - })} - - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx deleted file mode 100644 index 55697790c4ee9..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { GroupSelector } from './group_selector'; - -export function InventorySummary({ - totalEntities, - totalGroups, -}: { - totalEntities?: number; - totalGroups?: number; -}) { - const { euiTheme } = useEuiTheme(); - - const isGrouped = totalGroups !== undefined; - - return ( - - - - {totalEntities !== undefined && ( - - - - - - )} - {isGrouped ? ( - - - - - - ) : null} - - - - - - - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx deleted file mode 100644 index 9c263e39562f1..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx +++ /dev/null @@ -1,98 +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 { - ControlGroupRenderer, - ControlGroupRendererApi, - ControlGroupRuntimeState, -} from '@kbn/controls-plugin/public'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; -import { ControlPanels, useControlPanels } from '@kbn/observability-shared-plugin/public'; -import React, { useCallback, useEffect, useRef } from 'react'; -import { skip, Subscription } from 'rxjs'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; - -const controlPanelDefinitions: ControlPanels = { - [ENTITY_TYPE]: { - order: 0, - type: 'optionsListControl', - fieldName: ENTITY_TYPE, - width: 'small', - grow: false, - title: 'Type', - }, -}; - -export function ControlGroups() { - const { - isControlPanelsInitiated, - setIsControlPanelsInitiated, - dataView, - searchState, - onPanelFiltersChange, - } = useUnifiedSearchContext(); - const [controlPanels, setControlPanels] = useControlPanels(controlPanelDefinitions, dataView); - const subscriptions = useRef(new Subscription()); - - const getInitialInput = useCallback( - () => async () => { - const initialInput: Partial = { - chainingSystem: 'HIERARCHICAL', - labelPosition: 'oneLine', - initialChildControlState: controlPanels, - }; - - return { initialState: initialInput }; - }, - [controlPanels] - ); - - const loadCompleteHandler = useCallback( - (controlGroup: ControlGroupRendererApi) => { - if (!controlGroup) return; - - subscriptions.current.add( - controlGroup.filters$.pipe(skip(1)).subscribe((newFilters = []) => { - onPanelFiltersChange(newFilters); - }) - ); - - subscriptions.current.add( - controlGroup.getInput$().subscribe(({ initialChildControlState }) => { - if (!isControlPanelsInitiated) { - setIsControlPanelsInitiated(true); - } - setControlPanels(initialChildControlState); - }) - ); - }, - [isControlPanelsInitiated, onPanelFiltersChange, setControlPanels, setIsControlPanelsInitiated] - ); - - useEffect(() => { - const currentSubscriptions = subscriptions.current; - return () => { - currentSubscriptions.unsubscribe(); - }; - }, []); - - if (!dataView) { - return null; - } - - return ( -
        - -
        - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx new file mode 100644 index 0000000000000..0b4853e82a474 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx @@ -0,0 +1,146 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiFilterButton, + EuiFilterGroup, + EuiPopover, + EuiPopoverTitle, + EuiSelectable, + EuiSelectableOption, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useCallback, useMemo, useState } from 'react'; +import { entityTypesRt, type EntityType } from '../../../common/rt_types'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; +import { useKibana } from '../../hooks/use_kibana'; +import { groupEntityTypesByStatus } from '../../utils/group_entity_types_by_status'; + +export function EntityTypesMultiSelect() { + const inventoryRoute = useInventoryRouter(); + const { query } = useInventoryParams('/*'); + const { entityTypes: selectedEntityTypes } = useInventoryDecodedQueryParams(); + + const { + services: { inventoryAPIClient, telemetry }, + } = useKibana(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const { value, loading } = useInventoryAbortableAsync( + ({ signal }) => inventoryAPIClient.fetch('GET /internal/inventory/entities/types', { signal }), + [inventoryAPIClient] + ); + + const items = useMemo( + () => + value?.entityTypes.map((type): EuiSelectableOption => { + const checked = selectedEntityTypes?.[type]; + return { + label: type, + checked, + 'data-test-subj': `entityTypes_multiSelect_filter_selection_${type}`, + }; + }) || [], + [selectedEntityTypes, value?.entityTypes] + ); + + const registerEntityTypeFilteredEvent = useCallback( + ({ filterEntityTypes }: { filterEntityTypes: EntityType }) => { + const { entityTypesOff, entityTypesOn } = groupEntityTypesByStatus(filterEntityTypes); + + telemetry.reportEntityInventoryEntityTypeFiltered({ + include_entity_types: entityTypesOn, + exclude_entity_types: entityTypesOff, + }); + }, + [telemetry] + ); + + function handleEntityTypeChecked(nextItems: EntityType) { + registerEntityTypeFilteredEvent({ filterEntityTypes: nextItems }); + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + entityTypes: entityTypesRt.encode(nextItems), + }, + }); + } + + return ( + + setIsPopoverOpen((state) => !state)} + isSelected={isPopoverOpen} + numFilters={items.filter((item) => item.checked !== 'off').length} + hasActiveFilters={!!items.find((item) => item.checked === 'on')} + numActiveFilters={items.filter((item) => item.checked === 'on').length} + > + {i18n.translate('xpack.inventory.entityTypesMultSelect.typeFilterButtonLabel', { + defaultMessage: 'Type', + })} + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + panelPaddingSize="none" + > + { + handleEntityTypeChecked( + newOptions + .filter((item) => item.checked) + .reduce((acc, curr) => ({ ...acc, [curr.label]: curr.checked! }), {}) + ); + }} + isLoading={loading} + loadingMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.loading', + { defaultMessage: 'Loading types' } + )} + emptyMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.empty', + { defaultMessage: 'No types available' } + )} + noMatchesMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.notFound', + { defaultMessage: 'No types found' } + )} + > + {(list, search) => ( +
        + {search} + {list} +
        + )} +
        +
        +
        + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx index 3464c5749dbc3..16df0927df355 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx @@ -4,19 +4,24 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Query } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import type { SearchBarOwnProps } from '@kbn/unified-search-plugin/public/search_bar'; import deepEqual from 'fast-deep-equal'; import React, { useCallback, useEffect } from 'react'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; import { useKibana } from '../../hooks/use_kibana'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; import { getKqlFieldsWithFallback } from '../../utils/get_kql_field_names_with_fallback'; -import { ControlGroups } from './control_groups'; +import { EntityTypesMultiSelect } from './entity_types_multi_select'; export function SearchBar() { - const { refreshSubject$, dataView, searchState, onQueryChange } = useUnifiedSearchContext(); - + const { refreshSubject$, dataView } = useUnifiedSearchContext(); + const inventoryRoute = useInventoryRouter(); + const { + query, + query: { kuery }, + } = useInventoryParams('/*'); const { services: { unifiedSearch, @@ -30,44 +35,40 @@ export function SearchBar() { const { SearchBar: UnifiedSearchBar } = unifiedSearch.ui; const syncSearchBarWithUrl = useCallback(() => { - const query = searchState.query; - if (query && !deepEqual(queryStringService.getQuery(), query)) { - queryStringService.setQuery(query); + const _query = kuery ? { query: kuery, language: 'kuery' } : undefined; + if (_query && !deepEqual(queryStringService.getQuery(), _query)) { + queryStringService.setQuery(_query); } - if (!query) { + if (!_query) { queryStringService.clearQuery(); } - }, [searchState.query, queryStringService]); + }, [kuery, queryStringService]); useEffect(() => { syncSearchBarWithUrl(); }, [syncSearchBarWithUrl]); - const registerSearchSubmittedEvent = useCallback( - ({ searchQuery, searchIsUpdate }: { searchQuery?: Query; searchIsUpdate?: boolean }) => { - telemetry.reportEntityInventorySearchQuerySubmitted({ - kuery_fields: getKqlFieldsWithFallback(searchQuery?.query as string), - action: searchIsUpdate ? 'submit' : 'refresh', + const handleQuerySubmit = useCallback>( + ({ query: _query = { language: 'kuery', query: '' } }, isUpdate) => { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + kuery: _query?.query as string, + }, }); - }, - [telemetry] - ); - const handleQuerySubmit = useCallback>( - ({ query = { language: 'kuery', query: '' } }, isUpdate) => { - if (isUpdate) { - onQueryChange(query); - } else { + if (!isUpdate) { refreshSubject$.next(); } - registerSearchSubmittedEvent({ - searchQuery: query, - searchIsUpdate: isUpdate, + telemetry.reportEntityInventorySearchQuerySubmitted({ + kuery_fields: getKqlFieldsWithFallback(_query?.query as string), + action: isUpdate ? 'submit' : 'refresh', }); }, - [registerSearchSubmittedEvent, onQueryChange, refreshSubject$] + [inventoryRoute, query, telemetry, refreshSubject$] ); return ( @@ -75,16 +76,14 @@ export function SearchBar() { appName="Inventory" displayStyle="inPage" indexPatterns={dataView ? [dataView] : undefined} - renderQueryInputAppend={() => } + renderQueryInputAppend={() => } onQuerySubmit={handleQuerySubmit} placeholder={i18n.translate('xpack.inventory.searchBar.placeholder', { defaultMessage: 'Search for your entities by name or its metadata (e.g. entity.type : service)', })} showDatePicker={false} - showFilterBar - showQueryInput - showQueryMenu + showFilterBar={false} /> ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx deleted file mode 100644 index 1bec6dee990d1..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx +++ /dev/null @@ -1,117 +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 { EuiDataGridSorting } from '@elastic/eui'; -import { decodeOrThrow } from '@kbn/io-ts-utils'; -import React from 'react'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { - entityPaginationRt, - type EntityColumnIds, - type EntityPagination, -} from '../../../common/entities'; -import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; -import { useInventoryParams } from '../../hooks/use_inventory_params'; -import { useInventoryRouter } from '../../hooks/use_inventory_router'; -import { useKibana } from '../../hooks/use_kibana'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; -import { EntitiesGrid } from '../entities_grid'; -import { InventorySummary } from '../grouped_inventory/inventory_summary'; - -const paginationDecoder = decodeOrThrow(entityPaginationRt); - -export function UnifiedInventory() { - const { - services: { inventoryAPIClient }, - } = useKibana(); - const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } = - useUnifiedSearchContext(); - const { query } = useInventoryParams('/'); - const { sortDirection, sortField, pagination: paginationQuery } = query; - - let pagination: EntityPagination | undefined = {}; - const inventoryRoute = useInventoryRouter(); - try { - pagination = paginationDecoder(paginationQuery); - } catch (error) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: undefined, - }, - }); - window.location.reload(); - } - - const pageIndex = pagination?.unified ?? 0; - - const { - value = { entities: [] }, - loading, - refresh, - } = useInventoryAbortableAsync( - ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - params: { - query: { - sortDirection, - sortField, - esQuery: stringifiedEsQuery, - }, - }, - signal, - }); - } - }, - [inventoryAPIClient, sortDirection, sortField, isControlPanelsInitiated, stringifiedEsQuery] - ); - - useEffectOnce(() => { - const refreshSubscription = refreshSubject$.subscribe(refresh); - return () => refreshSubscription.unsubscribe(); - }); - - function handlePageChange(nextPage: number) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: entityPaginationRt.encode({ - ...pagination, - unified: nextPage, - }), - }, - }); - } - - function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - sortField: sorting.id as EntityColumnIds, - sortDirection: sorting.direction, - }, - }); - } - - return ( - <> - - - - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx index f5a71e80bd9a3..d43cba80dd177 100644 --- a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx @@ -7,7 +7,8 @@ import React, { createContext, useContext, type ReactChild } from 'react'; import { Subject } from 'rxjs'; import { DataView } from '@kbn/data-views-plugin/common'; -import { useAdHocInventoryDataView } from '../../hooks/use_adhoc_inventory_data_view'; +import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; +import { useAdHocDataView } from '../../hooks/use_adhoc_data_view'; interface InventorySearchBarContextType { searchBarContentSubject$: Subject<{ @@ -24,7 +25,7 @@ const InventorySearchBarContext = createContext({ }); export function InventorySearchBarContextProvider({ children }: { children: ReactChild }) { - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); return ( { expect(url).toBe('service-overview-url'); expect(mockGetRedirectUrl).toHaveBeenCalledWith({ serviceName: 'service-1', - environment: 'prod', }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts index 02a77b8f2afa1..ec193ae9dfcad 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts @@ -65,9 +65,6 @@ export const useDetailViewRedirect = () => { if (isBuiltinEntityOfType('service', entity)) { return serviceOverviewLocator?.getRedirectUrl({ serviceName: identityFieldsValue[identityFields[0]], - environment: entity.service?.environment - ? castArray(entity.service?.environment)[0] - : undefined, }); } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts index 33758c9df449d..dc9f5bf4a4740 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts @@ -4,74 +4,55 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - ENTITY_DEFINITION_ID, - ENTITY_DISPLAY_NAME, - ENTITY_LAST_SEEN, - ENTITY_TYPE, -} from '@kbn/observability-shared-plugin/common'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import type { InventoryEntity } from '../../common/entities'; +import { useAdHocDataView } from './use_adhoc_data_view'; +import { useFetchEntityDefinition } from './use_fetch_entity_definition'; import { useKibana } from './use_kibana'; -import { useUnifiedSearchContext } from './use_unified_search_context'; -const ACTIVE_COLUMNS = [ENTITY_DISPLAY_NAME, ENTITY_TYPE, ENTITY_LAST_SEEN]; - -export const useDiscoverRedirect = () => { +export const useDiscoverRedirect = (entity: InventoryEntity) => { const { services: { share, application, entityManager }, } = useKibana(); - - const { - dataView, - searchState: { query, filters, panelFilters }, - } = useUnifiedSearchContext(); - - const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); - - const getDiscoverEntitiesRedirectUrl = useCallback( - (entity?: InventoryEntity) => { - const entityKqlFilter = entity - ? entityManager.entityClient.asKqlFilter({ - entity: { - identity_fields: entity.entityIdentityFields, - }, - ...entity, - }) - : ''; - - const kueryWithEntityDefinitionFilters = [ - query.query, - entityKqlFilter, - `${ENTITY_DEFINITION_ID} : builtin*`, - ] - .filter(Boolean) - .join(' AND '); - - return application.capabilities.discover?.show - ? discoverLocator?.getRedirectUrl({ - indexPatternId: dataView?.id ?? '', - columns: ACTIVE_COLUMNS, - query: { query: kueryWithEntityDefinitionFilters, language: 'kuery' }, - filters: [...filters, ...panelFilters], - }) - : undefined; - }, - [ - application.capabilities.discover?.show, - dataView?.id, - discoverLocator, - entityManager.entityClient, - filters, - panelFilters, - query.query, - ] + const { entityDefinitions, isEntityDefinitionLoading } = useFetchEntityDefinition( + entity.entityDefinitionId ); - const getDiscoverRedirectUrl = useCallback( - (entity?: InventoryEntity) => getDiscoverEntitiesRedirectUrl(entity), - [getDiscoverEntitiesRedirectUrl] + const title = useMemo( + () => + !isEntityDefinitionLoading && entityDefinitions && entityDefinitions?.length > 0 + ? entityDefinitions[0]?.indexPatterns?.join(',') + : '', + [entityDefinitions, isEntityDefinitionLoading] ); - return { getDiscoverRedirectUrl }; + const { dataView } = useAdHocDataView(title); + + const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); + + const getDiscoverEntitiesRedirectUrl = useCallback(() => { + const entityKqlFilter = entity + ? entityManager.entityClient.asKqlFilter({ + entity: { + identity_fields: entity.entityIdentityFields, + }, + ...entity, + }) + : ''; + + return application.capabilities.discover?.show + ? discoverLocator?.getRedirectUrl({ + indexPatternId: dataView?.id ?? '', + query: { query: entityKqlFilter, language: 'kuery' }, + }) + : undefined; + }, [ + application.capabilities.discover?.show, + dataView?.id, + discoverLocator, + entity, + entityManager.entityClient, + ]); + + return { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading }; }; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts new file mode 100644 index 0000000000000..9f6a0232891b2 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import { useKibana } from './use_kibana'; + +export const useFetchEntityDefinition = (id: string) => { + const { + services: { entityManager }, + } = useKibana(); + + const { value, loading } = useAbortableAsync( + ({ signal }) => { + return entityManager.entityClient.getEntityDefinition(id); + }, + [entityManager.entityClient, id] + ); + + return { + entityDefinitions: value?.definitions, + isEntityDefinitionLoading: loading, + }; +}; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts new file mode 100644 index 0000000000000..c02a33a8c06f7 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { useCallback, useMemo } from 'react'; +import { + entityPaginationRt, + entityTypesRt, + type EntityPagination, + type EntityType, +} from '../../common/rt_types'; +import { useInventoryParams } from './use_inventory_params'; +import { useInventoryRouter } from './use_inventory_router'; + +const entityTypeDecoder = decodeOrThrow(entityTypesRt); +const paginationDecoder = decodeOrThrow(entityPaginationRt); + +export function useInventoryDecodedQueryParams() { + const inventoryRoute = useInventoryRouter(); + const { + query, + query: { entityTypes, pagination }, + } = useInventoryParams('/*'); + + const resetUrlParam = useCallback( + (queryParamName: string) => { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + [queryParamName]: undefined, + }, + }); + }, + [inventoryRoute, query] + ); + + const selectedEntityTypes: EntityType = useMemo(() => { + try { + return entityTypeDecoder(entityTypes) || {}; + } catch (e) { + resetUrlParam('entityTypes'); + return {}; + } + }, [entityTypes, resetUrlParam]); + + const selectedPagination: EntityPagination = useMemo(() => { + try { + return paginationDecoder(pagination) || {}; + } catch (error) { + resetUrlParam('pagination'); + return {}; + } + }, [pagination, resetUrlParam]); + + return { entityTypes: selectedEntityTypes, pagination: selectedPagination }; +} diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts index 94df3a035f3bb..c5715fb1d50b6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts @@ -4,161 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { buildEsQuery, type Filter, fromKueryExpression, type Query } from '@kbn/es-query'; import createContainer from 'constate'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { map, Subject, Subscription, tap } from 'rxjs'; -import { generateFilters } from '@kbn/data-plugin/public'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import deepEqual from 'fast-deep-equal'; -import { i18n } from '@kbn/i18n'; -import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public'; -import { useAdHocInventoryDataView } from './use_adhoc_inventory_data_view'; -import { useUnifiedSearchUrl } from './use_unified_search_url'; -import { useKibana } from './use_kibana'; +import { useState } from 'react'; +import { Subject } from 'rxjs'; +import { ENTITIES_LATEST_ALIAS } from '../../common/entities'; +import { useAdHocDataView } from './use_adhoc_data_view'; function useUnifiedSearch() { - const [isControlPanelsInitiated, setIsControlPanelsInitiated] = useState(false); - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); const [refreshSubject$] = useState>(new Subject()); - const { searchState, setSearchState } = useUnifiedSearchUrl(); - const kibanaQuerySettings = useKibanaQuerySettings(); - const { - services: { - data: { - query: { filterManager: filterManagerService, queryString: queryStringService }, - }, - notifications, - }, - } = useKibana(); - - useEffectOnce(() => { - if (!deepEqual(filterManagerService.getFilters(), searchState.filters)) { - filterManagerService.setFilters( - searchState.filters.map((item) => ({ - ...item, - meta: { ...item.meta, index: dataView?.id }, - })) - ); - } - - if (!deepEqual(queryStringService.getQuery(), searchState.query)) { - queryStringService.setQuery(searchState.query); - } - }); - - useEffect(() => { - const subscription = new Subscription(); - subscription.add( - filterManagerService - .getUpdates$() - .pipe( - map(() => filterManagerService.getFilters()), - tap((filters) => setSearchState({ type: 'SET_FILTERS', filters })) - ) - .subscribe() - ); - - subscription.add( - queryStringService - .getUpdates$() - .pipe( - map(() => queryStringService.getQuery() as Query), - tap((query) => setSearchState({ type: 'SET_QUERY', query })) - ) - .subscribe() - ); - - return () => { - subscription.unsubscribe(); - }; - }, [filterManagerService, queryStringService, setSearchState]); - - const validateQuery = useCallback( - (query: Query) => { - fromKueryExpression(query.query, kibanaQuerySettings); - }, - [kibanaQuerySettings] - ); - - const onQueryChange = useCallback( - (query: Query) => { - try { - validateQuery(query); - setSearchState({ type: 'SET_QUERY', query }); - } catch (e) { - const err = e as Error; - notifications.toasts.addDanger({ - title: i18n.translate('xpack.inventory.unifiedSearchContext.queryError', { - defaultMessage: 'Error while updating the new query', - }), - text: err.message, - }); - } - }, - [validateQuery, setSearchState, notifications.toasts] - ); - - const onPanelFiltersChange = useCallback( - (panelFilters: Filter[]) => { - setSearchState({ type: 'SET_PANEL_FILTERS', panelFilters }); - }, - [setSearchState] - ); - - const onFiltersChange = useCallback( - (filters: Filter[]) => { - setSearchState({ type: 'SET_FILTERS', filters }); - }, - [setSearchState] - ); - - const addFilter = useCallback( - ({ - fieldName, - operation, - value, - }: { - fieldName: string; - value: string; - operation: '+' | '-'; - }) => { - if (dataView) { - const newFilters = generateFilters( - filterManagerService, - fieldName, - value, - operation, - dataView - ); - setSearchState({ type: 'SET_FILTERS', filters: [...newFilters, ...searchState.filters] }); - } - }, - [dataView, filterManagerService, searchState.filters, setSearchState] - ); - - const stringifiedEsQuery = useMemo(() => { - if (dataView) { - return JSON.stringify( - buildEsQuery(dataView, searchState.query, [ - ...searchState.panelFilters, - ...searchState.filters, - ]) - ); - } - }, [dataView, searchState.panelFilters, searchState.filters, searchState.query]); return { - isControlPanelsInitiated, - setIsControlPanelsInitiated, dataView, refreshSubject$, - searchState, - addFilter, - stringifiedEsQuery, - onQueryChange, - onPanelFiltersChange, - onFiltersChange, }; } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts deleted file mode 100644 index 17cf0ef0d9597..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts +++ /dev/null @@ -1,100 +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 { FilterStateStore } from '@kbn/es-query'; -import { useUrlState } from '@kbn/observability-shared-plugin/public'; -import { enumeration } from '@kbn/securitysolution-io-ts-types'; -import { fold } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; -import * as t from 'io-ts'; -import { useReducer } from 'react'; -import deepEqual from 'fast-deep-equal'; - -const FilterRT = t.intersection([ - t.type({ - meta: t.partial({ - alias: t.union([t.null, t.string]), - disabled: t.boolean, - negate: t.boolean, - controlledBy: t.string, - group: t.string, - index: t.string, - isMultiIndex: t.boolean, - type: t.string, - key: t.string, - params: t.any, - value: t.any, - }), - }), - t.partial({ - query: t.record(t.string, t.any), - $state: t.type({ - store: enumeration('FilterStateStore', FilterStateStore), - }), - }), -]); -const FiltersRT = t.array(FilterRT); - -const QueryStateRT = t.type({ - language: t.string, - query: t.union([t.string, t.record(t.string, t.any)]), -}); - -const SearchStateRT = t.type({ - panelFilters: FiltersRT, - filters: FiltersRT, - query: QueryStateRT, -}); - -const encodeUrlState = SearchStateRT.encode; -const decodeUrlState = (value: unknown) => { - return pipe(SearchStateRT.decode(value), fold(constant(undefined), identity)); -}; - -type SearchState = t.TypeOf; - -const INITIAL_VALUE: SearchState = { - query: { language: 'kuery', query: '' }, - panelFilters: [], - filters: [], -}; - -export type StateAction = - | { type: 'SET_FILTERS'; filters: SearchState['filters'] } - | { type: 'SET_QUERY'; query: SearchState['query'] } - | { type: 'SET_PANEL_FILTERS'; panelFilters: SearchState['panelFilters'] }; - -const reducer = (state: SearchState, action: StateAction): SearchState => { - switch (action.type) { - case 'SET_FILTERS': - return { ...state, filters: action.filters }; - case 'SET_QUERY': - return { ...state, query: action.query }; - case 'SET_PANEL_FILTERS': - return { ...state, panelFilters: action.panelFilters }; - default: - return state; - } -}; - -export function useUnifiedSearchUrl() { - const [urlState, setUrlState] = useUrlState({ - defaultState: INITIAL_VALUE, - decodeUrlState, - encodeUrlState, - urlStateKey: '_a', - writeDefaultState: true, - }); - - const [searchState, setSearchState] = useReducer(reducer, urlState); - - if (!deepEqual(searchState, urlState)) { - setUrlState(searchState); - } - - return { searchState, setSearchState }; -} diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx index f34df1a3c8b32..6eab905a40692 100644 --- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -4,12 +4,83 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { flattenObject } from '@kbn/observability-utils-common/object/flatten_object'; import React from 'react'; -import { GroupedInventory } from '../../components/grouped_inventory'; -import { UnifiedInventory } from '../../components/unified_inventory'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { EntitiesSummary } from '../../components/entities_summary'; +import { EntityGroupAccordion } from '../../components/entity_group_accordion'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useKibana } from '../../hooks/use_kibana'; +import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; +import { GroupBySelector } from '../../components/group_by_selector'; +import { groupEntityTypesByStatus } from '../../utils/group_entity_types_by_status'; export function InventoryPage() { - const { query } = useInventoryParams('/'); - return query.view === 'unified' ? : ; + const { + services: { inventoryAPIClient }, + } = useKibana(); + const { refreshSubject$ } = useUnifiedSearchContext(); + const { + query: { kuery }, + } = useInventoryParams('/'); + const { entityTypes } = useInventoryDecodedQueryParams(); + + const { + value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 }, + refresh, + loading, + } = useInventoryAbortableAsync( + ({ signal }) => { + const { entityTypesOff, entityTypesOn } = groupEntityTypesByStatus(entityTypes); + return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', { + params: { + path: { + field: ENTITY_TYPE, + }, + query: { + includeEntityTypes: entityTypesOn.length ? JSON.stringify(entityTypesOn) : undefined, + excludeEntityTypes: entityTypesOff.length ? JSON.stringify(entityTypesOff) : undefined, + kuery, + }, + }, + signal, + }); + }, + [entityTypes, inventoryAPIClient, kuery] + ); + + useEffectOnce(() => { + const refreshSubscription = refreshSubject$.subscribe(refresh); + return () => refreshSubscription.unsubscribe(); + }); + + return ( + <> + + + + + + + + + + {value.groups.map((group) => { + const groupValue = flattenObject(group)[value.groupBy]; + return ( + + ); + })} + + ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx index bf5f8324aab25..32db48130a89c 100644 --- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx @@ -7,9 +7,9 @@ import { Outlet, createRouter } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; +import { defaultEntitySortField, entityColumnIdsRt } from '../../common/entities'; import { InventoryPageTemplate } from '../components/inventory_page_template'; import { InventoryPage } from '../pages/inventory_page'; -import { defaultEntitySortField, entityColumnIdsRt, entityViewRt } from '../../common/entities'; /** * The array of route definitions to be used when the application @@ -29,10 +29,9 @@ const inventoryRoutes = { sortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), t.partial({ - view: entityViewRt, pagination: t.string, - _a: t.string, - controlPanels: t.string, + entityTypes: t.string, + kuery: t.string, }), ]), }), @@ -40,7 +39,6 @@ const inventoryRoutes = { query: { sortField: defaultEntitySortField, sortDirection: 'desc', - view: 'grouped', }, }, children: { diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts index c4c238fba5f8f..d7806c2f6cb2e 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts @@ -14,6 +14,7 @@ import { type EntityInventoryViewedParams, type EntityInventorySearchQuerySubmittedParams, type EntityViewClickedParams, + type EntityInventoryEntityTypeFilteredParams, } from './types'; export class TelemetryClient implements ITelemetryClient { @@ -36,4 +37,10 @@ export class TelemetryClient implements ITelemetryClient { public reportEntityViewClicked = (params: EntityViewClickedParams) => { this.analytics.reportEvent(TelemetryEventTypes.ENTITY_VIEW_CLICKED, params); }; + + public reportEntityInventoryEntityTypeFiltered = ( + params: EntityInventoryEntityTypeFilteredParams + ) => { + this.analytics.reportEvent(TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, params); + }; } diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts index ec2623fe2a2cc..707852f9f3cd6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts @@ -58,6 +58,30 @@ const searchQuerySubmittedEventType: TelemetryEvent = { }, }; +const entityInventoryEntityTypeFilteredEventType: TelemetryEvent = { + eventType: TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, + schema: { + include_entity_types: { + type: 'array', + items: { + type: 'keyword', + _meta: { + description: 'List of Entity types used to filter for.', + }, + }, + }, + exclude_entity_types: { + type: 'array', + items: { + type: 'keyword', + _meta: { + description: 'List of Entity types used to filter out.', + }, + }, + }, + }, +}; + const entityViewClickedEventType: TelemetryEvent = { eventType: TelemetryEventTypes.ENTITY_VIEW_CLICKED, schema: { @@ -81,4 +105,5 @@ export const inventoryTelemetryEventBasedTypes = [ entityInventoryViewedEventType, searchQuerySubmittedEventType, entityViewClickedEventType, + entityInventoryEntityTypeFilteredEventType, ]; diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts index 639b771788f5b..6a4854f754831 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts @@ -13,6 +13,7 @@ import { type EntityViewClickedParams, type EntityInventorySearchQuerySubmittedParams, TelemetryEventTypes, + EntityInventoryEntityTypeFilteredParams, } from './types'; describe('TelemetryService', () => { @@ -145,4 +146,24 @@ describe('TelemetryService', () => { ); }); }); + + describe('#reportEntityInventoryEntityTypeFiltered', () => { + it('should report entity type filtered with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + const params: EntityInventoryEntityTypeFilteredParams = { + include_entity_types: ['container'], + exclude_entity_types: ['service'], + }; + + telemetry.reportEntityInventoryEntityTypeFiltered(params); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, + params + ); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts index 0d56f44c2c2f2..e8ce3eb94e9ba 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts @@ -30,6 +30,11 @@ export interface EntityInventorySearchQuerySubmittedParams { action: 'submit' | 'refresh'; } +export interface EntityInventoryEntityTypeFilteredParams { + include_entity_types: string[]; + exclude_entity_types: string[]; +} + export interface EntityViewClickedParams { entity_type: string; view_type: 'detail' | 'flyout'; @@ -39,7 +44,8 @@ export type TelemetryEventParams = | InventoryAddDataParams | EntityInventoryViewedParams | EntityInventorySearchQuerySubmittedParams - | EntityViewClickedParams; + | EntityViewClickedParams + | EntityInventoryEntityTypeFilteredParams; export interface ITelemetryClient { reportInventoryAddData(params: InventoryAddDataParams): void; @@ -48,6 +54,7 @@ export interface ITelemetryClient { params: EntityInventorySearchQuerySubmittedParams ): void; reportEntityViewClicked(params: EntityViewClickedParams): void; + reportEntityInventoryEntityTypeFiltered(params: EntityInventoryEntityTypeFilteredParams): void; } export enum TelemetryEventTypes { diff --git a/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.ts b/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.ts new file mode 100644 index 0000000000000..f842663dd56e9 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.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 { EntityType } from '../../common/rt_types'; + +export function groupEntityTypesByStatus(entityTypes: EntityType) { + const entityTypesKeys = Object.keys(entityTypes); + return { + entityTypesOn: entityTypesKeys.filter((key) => entityTypes[key] === 'on').sort(), + entityTypesOff: entityTypesKeys.filter((key) => entityTypes[key] === 'off').sort(), + }; +} diff --git a/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts b/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts similarity index 93% rename from x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts rename to x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts index 150e946fd98d6..878abd516e5bd 100644 --- a/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts +++ b/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { InventoryRouteHandlerResources } from '../../routes/types'; export type AlertsClient = Awaited>; @@ -18,13 +19,7 @@ export async function createAlertsClient({ }: Pick) { const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const alertsIndices = await alertsClient.getAuthorizedAlertsIndices([ - 'logs', - 'infrastructure', - 'apm', - 'slo', - 'observability', - ]); + const alertsIndices = await alertsClient.getAuthorizedAlertsIndices(OBSERVABILITY_RULE_TYPE_IDS); if (!alertsIndices || isEmpty(alertsIndices)) { throw Error('No alert indices exist'); diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts index 816b3c6af6ec2..ead3109060d13 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts @@ -5,26 +5,43 @@ * 2.0. */ -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import { kqlQuery } from '@kbn/observability-plugin/server'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, - type EntityGroup, MAX_NUMBER_OF_ENTITIES, + type EntityGroup, } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; export async function getEntityGroupsBy({ inventoryEsClient, field, - esQuery, + kuery, + includeEntityTypes = [], + excludeEntityTypes = [], }: { inventoryEsClient: ObservabilityElasticsearchClient; field: string; - esQuery?: QueryDslQueryContainer; + includeEntityTypes?: string[]; + excludeEntityTypes?: string[]; + kuery?: string; }): Promise { const from = `FROM ${ENTITIES_LATEST_ALIAS}`; const where = [getBuiltinEntityDefinitionIdESQLWhereClause()]; + const params: ScalarValue[] = []; + + if (includeEntityTypes.length) { + where.push(`WHERE ${ENTITY_TYPE} IN (${includeEntityTypes.map(() => '?').join()})`); + params.push(...includeEntityTypes); + } + + if (excludeEntityTypes.length) { + where.push(`WHERE ${ENTITY_TYPE} NOT IN (${excludeEntityTypes.map(() => '?').join()})`); + params.push(...excludeEntityTypes); + } const group = `STATS count = COUNT(*) by ${field}`; const sort = `SORT ${field} asc`; @@ -35,7 +52,8 @@ export async function getEntityGroupsBy({ 'get_entities_groups', { query, - filter: esQuery, + filter: { bool: { filter: kqlQuery(kuery) } }, + params, }, { transform: 'plain' } ); diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 9dcf17250ad68..83f576220d12a 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -5,19 +5,20 @@ * 2.0. */ -import type { QueryDslQueryContainer, ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import type { ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import { kqlQuery } from '@kbn/observability-plugin/server'; import { ENTITY_DISPLAY_NAME, ENTITY_LAST_SEEN, ENTITY_TYPE, } from '@kbn/observability-shared-plugin/common'; -import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { unflattenObject } from '@kbn/observability-utils-common/object/unflatten_object'; +import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, - InventoryEntity, MAX_NUMBER_OF_ENTITIES, type EntityColumnIds, + type InventoryEntity, } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; @@ -35,13 +36,13 @@ export async function getLatestEntities({ inventoryEsClient, sortDirection, sortField, - esQuery, + kuery, entityTypes, }: { inventoryEsClient: ObservabilityElasticsearchClient; sortDirection: 'asc' | 'desc'; sortField: EntityColumnIds; - esQuery?: QueryDslQueryContainer; + kuery?: string; entityTypes?: string[]; }): Promise { // alertsCount doesn't exist in entities index. Ignore it and sort by entity.lastSeenTimestamp by default. @@ -78,7 +79,7 @@ export async function getLatestEntities({ 'get_latest_entities', { query, - filter: esQuery, + filter: { bool: { filter: kqlQuery(kuery) } }, params, }, { transform: 'plain' } diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts index 0f1ace0407233..d4c69505a4637 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts @@ -7,7 +7,7 @@ import { termQuery } from '@kbn/observability-plugin/server'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE } from '@kbn/rule-data-utils'; -import { AlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; +import { AlertsClient } from '../../lib/create_alerts_client/create_alerts_client'; import { getGroupByTermsAgg } from './get_group_by_terms_agg'; import { IdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts index 992729a9c1aa0..c4a0a21f50eb2 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts @@ -12,7 +12,7 @@ import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/ import * as t from 'io-ts'; import { orderBy } from 'lodash'; import { InventoryEntity, entityColumnIdsRt } from '../../../common/entities'; -import { createAlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; +import { createAlertsClient } from '../../lib/create_alerts_client/create_alerts_client'; import { createInventoryServerRoute } from '../create_inventory_server_route'; import { getEntityGroupsBy } from './get_entity_groups'; import { getEntityTypes } from './get_entity_types'; @@ -47,7 +47,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ sortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), t.partial({ - esQuery: jsonRt.pipe(t.UnknownRecord), + kuery: t.string, entityTypes: jsonRt.pipe(t.array(t.string)), }), ]), @@ -69,7 +69,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ plugin: `@kbn/${INVENTORY_APP_ID}-plugin`, }); - const { sortDirection, sortField, esQuery, entityTypes } = params.query; + const { sortDirection, sortField, kuery, entityTypes } = params.query; const [alertsClient, latestEntities] = await Promise.all([ createAlertsClient({ plugins, request }), @@ -77,7 +77,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ inventoryEsClient, sortDirection, sortField, - esQuery, + kuery, entityTypes, }), ]); @@ -113,7 +113,9 @@ export const groupEntitiesByRoute = createInventoryServerRoute({ t.type({ path: t.type({ field: t.literal(ENTITY_TYPE) }) }), t.partial({ query: t.partial({ - esQuery: jsonRt.pipe(t.UnknownRecord), + includeEntityTypes: jsonRt.pipe(t.array(t.string)), + excludeEntityTypes: jsonRt.pipe(t.array(t.string)), + kuery: t.string, }), }), ]), @@ -129,12 +131,14 @@ export const groupEntitiesByRoute = createInventoryServerRoute({ }); const { field } = params.path; - const { esQuery } = params.query ?? {}; + const { kuery, includeEntityTypes, excludeEntityTypes } = params.query ?? {}; const groups = await getEntityGroupsBy({ inventoryEsClient, field, - esQuery, + kuery, + includeEntityTypes, + excludeEntityTypes, }); const entitiesCount = groups.reduce((acc, group) => acc + group.count, 0); diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 5094201cc2975..561ca62eaf97e 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -54,11 +54,10 @@ "@kbn/storybook", "@kbn/dashboard-plugin", "@kbn/deeplinks-analytics", - "@kbn/controls-plugin", - "@kbn/securitysolution-io-ts-types", "@kbn/react-hooks", "@kbn/observability-utils-common", "@kbn/observability-utils-browser", - "@kbn/observability-utils-server" + "@kbn/observability-utils-server", + "@kbn/kibana-utils-plugin" ] } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts index bf1070307742a..c5eaf3f4c3d8e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { InvestigateAppRouteHandlerResources } from '../routes/types'; export type AlertsClient = Awaited>; @@ -18,14 +19,7 @@ export async function getAlertsClient({ }: Pick) { const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const alertsIndices = await alertsClient.getAuthorizedAlertsIndices([ - 'logs', - 'infrastructure', - 'apm', - 'slo', - 'uptime', - 'observability', - ]); + const alertsIndices = await alertsClient.getAuthorizedAlertsIndices(OBSERVABILITY_RULE_TYPE_IDS); if (!alertsIndices || isEmpty(alertsIndices)) { throw Error('No alert indices exist'); diff --git a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc index ee8881a4479e7..02fcff85404a0 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/logs-data-access-plugin", - "owner": ["@elastic/obs-knowledge-team", "@elastic/obs-ux-logs-team"], + "owner": ["@elastic/obs-ux-logs-team"], "plugin": { "id": "logsDataAccess", "server": true, diff --git a/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts b/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts index f329907f145ef..e44b9cadcae08 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts +++ b/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts @@ -12,23 +12,32 @@ import { RegisterServicesParams } from '../register_services'; export function createLogSourcesService(params: RegisterServicesParams): LogSourcesService { const { uiSettings } = params.deps; - return { - async getLogSources() { - const logSources = uiSettings.get(OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID); - return logSources.map((logSource) => ({ - indexPattern: logSource, - })); - }, - async getFlattenedLogSources() { - const logSources = await this.getLogSources(); - return flattenLogSources(logSources); - }, - async setLogSources(sources: LogSource[]) { - await uiSettings.set( - OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, - sources.map((source) => source.indexPattern) - ); - return; - }, + + const getLogSources = async () => { + const logSources = uiSettings.get(OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID); + return logSources.map((logSource) => ({ + indexPattern: logSource, + })); + }; + + const getFlattenedLogSources = async () => { + const logSources = await getLogSources(); + return flattenLogSources(logSources); + }; + + const setLogSources = async (sources: LogSource[]) => { + await uiSettings.set( + OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, + sources.map((source) => source.indexPattern) + ); + return; + }; + + const logSourcesService: LogSourcesService = { + getLogSources, + getFlattenedLogSources, + setLogSources, }; + + return logSourcesService; } diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index f5e9f76c2ace6..69539098f2463 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -18,11 +18,13 @@ "observabilityShared", "share", "usageCollection", + "embeddable", ], "optionalPlugins": [ "observabilityAIAssistant", ], - "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedDocViewer"], + "requiredBundles": ["kibanaUtils", "kibanaReact"], "extraPublicDirs": ["common"] } } + \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx index 0321651607ed1..e6ec419ae8b0f 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx @@ -61,7 +61,6 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { logsDataAccess, observabilityAIAssistant, share, - fieldFormats, } = plugins; const logViews = this.logViews.start({ @@ -72,14 +71,14 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { }); const LogsOverview = createLogsOverview({ - core, charts, logsDataAccess, search: data.search.search, + searchSource: data.search.searchSource, uiSettings: settings, share, dataViews, - fieldFormats, + embeddable: plugins.embeddable, }); if (!observabilityAIAssistant) { diff --git a/x-pack/plugins/observability_solution/logs_shared/public/test_utils/entries.ts b/x-pack/plugins/observability_solution/logs_shared/public/test_utils/entries.ts index 5277f49b1175e..dc6a1526bba0c 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/test_utils/entries.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/test_utils/entries.ts @@ -5,7 +5,7 @@ * 2.0. */ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { LogEntry } from '../../common/log_entry'; import { LogViewColumnConfiguration } from '../../common/log_views'; @@ -60,15 +60,15 @@ export function generateFakeEntries( function fakeColumnValue(field: string): string { switch (field) { case 'message': - return faker.fake( - '{{internet.ip}} - [{{date.past}}] "GET {{internet.url}} HTTP/1.1" 200 {{random.number}} "-" "{{internet.userAgent}}"' + return faker.helpers.fake( + '{{internet.ip}} - [{{date.past}}] "GET {{internet.url}} HTTP/1.1" 200 {{number.int}} "-" "{{internet.userAgent}}"' ); case 'event.dataset': - return faker.fake('{{hacker.noun}}.{{hacker.noun}}'); + return faker.helpers.fake('{{hacker.noun}}.{{hacker.noun}}'); case 'log.file.path': return faker.system.filePath(); case 'log.level': - return faker.random.arrayElement(['debug', 'info', 'warn', 'error']); + return faker.helpers.arrayElement(['debug', 'info', 'warn', 'error']); case 'host.name': return faker.hacker.noun(); default: diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index e2435fa1f4915..90bbd89f2481d 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -15,6 +15,8 @@ import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai- import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; import type { SelfContainedLogsOverview } from './components/logs_overview'; @@ -46,6 +48,8 @@ export interface LogsSharedClientStartDeps { share: SharePluginStart; uiActions: UiActionsStart; fieldFormats: FieldFormatsStart; + embeddable: EmbeddableStart; + savedSearch: SavedSearchPublicPluginStart; } export type LogsSharedClientCoreSetup = CoreSetup< diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index f171c79afccd0..acaed5073a176 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -49,5 +49,7 @@ "@kbn/charts-plugin", "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", + "@kbn/embeddable-plugin", + "@kbn/saved-search-plugin", ] } diff --git a/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc index 17ad2991f315d..3188d318b64cb 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc @@ -1,10 +1,7 @@ { "type": "plugin", "id": "@kbn/metrics-data-access-plugin", - "owner": [ - "@elastic/obs-knowledge-team", - "@elastic/obs-ux-infra_services-team" - ], + "owner": ["@elastic/obs-ux-infra_services-team"], "group": "observability", "visibility": "private", "description": "Exposes utilities for accessing metrics data", diff --git a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts index 246988ed96307..6449fcc30b2dc 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts @@ -19,7 +19,7 @@ import { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/serv import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; @@ -27,7 +27,7 @@ import { VersionedRouteConfig } from '@kbn/core-http-server'; import { MetricsDataPluginSetup } from '../../../types'; export interface InfraServerPluginSetupDeps { - alerting: AlertingPluginContract; + alerting: AlertingServerSetup; data: DataPluginSetup; home: HomeServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/observability_solution/observability/common/constants.ts b/x-pack/plugins/observability_solution/observability/common/constants.ts index 0286e4bef0825..785f1caf4cb6d 100644 --- a/x-pack/plugins/observability_solution/observability/common/constants.ts +++ b/x-pack/plugins/observability_solution/observability/common/constants.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { + AlertConsumers, + STACK_RULE_TYPE_IDS_SUPPORTED_BY_OBSERVABILITY, + OBSERVABILITY_RULE_TYPE_IDS, +} from '@kbn/rule-data-utils'; import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { RuleCreationValidConsumer } from '@kbn/triggers-actions-ui-plugin/public'; @@ -20,6 +24,7 @@ export const observabilityAlertFeatureIds: ValidFeatureId[] = [ AlertConsumers.UPTIME, AlertConsumers.SLO, AlertConsumers.OBSERVABILITY, + AlertConsumers.ALERTS, ]; export const observabilityRuleCreationValidConsumers: RuleCreationValidConsumer[] = [ @@ -29,3 +34,8 @@ export const observabilityRuleCreationValidConsumers: RuleCreationValidConsumer[ ]; export const EventsAsUnit = 'events'; + +export const OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES = [ + ...OBSERVABILITY_RULE_TYPE_IDS, + ...STACK_RULE_TYPE_IDS_SUPPORTED_BY_OBSERVABILITY, +]; diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx index b7da84869679a..d64d8dcbb1a41 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx @@ -12,8 +12,8 @@ import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; import { ObservabilityAlertSearchBarProps, Services } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; import { render } from '../../utils/test_helper'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../common/constants'; const getAlertsSearchBarMock = jest.fn(); const ALERT_SEARCH_BAR_DATA_TEST_SUBJ = 'alerts-search-bar'; @@ -69,7 +69,7 @@ describe('ObservabilityAlertSearchBar', () => { expect(getAlertsSearchBarMock).toHaveBeenCalledWith( expect.objectContaining({ appName: 'testAppName', - featureIds: observabilityAlertFeatureIds, + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, rangeFrom: 'now-15m', rangeTo: 'now', query: '', diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx index 863855bbbb3b8..dd855829edf6f 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx @@ -11,8 +11,8 @@ import React, { useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { Filter, Query } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../common/constants'; import { AlertsStatusFilter } from './components'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; import { ALERT_STATUS_QUERY, DEFAULT_QUERIES, DEFAULT_QUERY_STRING } from './constants'; import { ObservabilityAlertSearchBarProps } from './types'; import { buildEsQuery } from '../../utils/build_es_query'; @@ -161,7 +161,7 @@ export function ObservabilityAlertSearchBar({ ['services'], @@ -25,7 +24,7 @@ interface GetPersistentControlsParams { export const getPersistentControlsHook = ({ groupingId, - featureIds, + ruleTypeIds, maxGroupingLevels = 3, services: { dataViews, http, notifications }, }: GetPersistentControlsParams) => @@ -43,7 +42,7 @@ export const getPersistentControlsHook = ); const { dataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts: notifications.toasts, diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx index dfcf01e4e4c13..614a842963868 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { EuiPanel, EuiFlexGroup, @@ -17,12 +16,10 @@ import { EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ALERT_INSTANCE_ID, ALERT_RULE_UUID, type AlertConsumers } from '@kbn/rule-data-utils'; +import { ALERT_INSTANCE_ID, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import { useAlertsHistory } from '@kbn/observability-alert-details'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; import { convertTo } from '../../../../common/utils/formatters'; -import { useFetchRuleTypes } from '../../../hooks/use_fetch_rule_types'; -import { useGetFilteredRuleTypes } from '../../../hooks/use_get_filtered_rule_types'; import { useKibana } from '../../../utils/kibana_react'; import { TopAlert } from '../../..'; import { getDefaultAlertSummaryTimeRange } from '../../../utils/alert_summary_widget'; @@ -43,19 +40,11 @@ export function AlertHistoryChart({ rule, alert }: Props) { notifications, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, } = useKibana().services; + const instanceId = alert.fields[ALERT_INSTANCE_ID]; - const filteredRuleTypes = useGetFilteredRuleTypes(); - const { ruleTypes } = useFetchRuleTypes({ - filterByRuleTypeIds: filteredRuleTypes, - }); - const ruleType = ruleTypes?.find((type) => type.id === rule?.ruleTypeId); - const featureIds = - rule?.consumer === ALERTING_FEATURE_ID && ruleType?.producer - ? [ruleType.producer as AlertConsumers] - : rule - ? [rule.consumer as AlertConsumers] - : []; const ruleId = alert.fields[ALERT_RULE_UUID]; + const ruleTypeIds = [rule.ruleTypeId]; + const consumers = [rule.consumer]; const { data: { avgTimeToRecoverUS, totalTriggeredAlerts }, @@ -63,7 +52,8 @@ export function AlertHistoryChart({ rule, alert }: Props) { isError, } = useAlertsHistory({ http, - featureIds, + ruleTypeIds, + consumers, ruleId: rule.id, dateRange, instanceId, @@ -162,7 +152,8 @@ export function AlertHistoryChart({ rule, alert }: Props) { {esQuery && ( - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} defaultFilters={ALERT_STATUS_FILTER[alertSearchBarStateProps.status] ?? DEFAULT_FILTERS} from={alertSearchBarStateProps.rangeFrom} to={alertSearchBarStateProps.rangeTo} @@ -149,7 +153,8 @@ export function InternalRelatedAlerts({ alert }: Props) { return ( {esQuery && ( - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} defaultFilters={ ALERT_STATUS_FILTER[alertSearchBarStateProps.status] ?? DEFAULT_FILTERS } @@ -286,7 +291,8 @@ function InternalAlertsPage() { return ( ; ruleId: string; ruleType: any; @@ -49,7 +49,7 @@ interface Props { export function RuleDetailsTabs({ activeTabId, esQuery, - featureIds, + ruleTypeIds, rule, ruleId, ruleType, @@ -90,12 +90,13 @@ export function RuleDetailsTabs({ - {esQuery && featureIds && ( + {esQuery && ruleTypeIds && ( type.id === rule?.ruleTypeId); - const isEditable = isRuleEditable({ capabilities, rule, ruleType, ruleTypeRegistry }); - const featureIds = - rule?.consumer === ALERTING_FEATURE_ID && ruleType?.producer - ? [ruleType.producer as AlertConsumers] - : rule - ? [rule.consumer as AlertConsumers] - : []; - const ruleStatusMessage = rule?.executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License ? rulesStatusesTranslationsMapping.noLicense @@ -234,7 +229,8 @@ export function RuleDetailsPage() { >; @@ -75,7 +76,8 @@ export function RulesTab({ setRefresh, stateRefresh }: RulesTabProps) { return ( >) => { diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts index c214939bdec88..300dcda5e4f0f 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IBasePath, Logger } from '@kbn/core/server'; import { CustomThresholdLocators } from './custom_threshold/custom_threshold_executor'; import { ObservabilityConfig } from '../..'; import { thresholdRuleType } from './custom_threshold/register_custom_threshold_rule_type'; export function registerRuleTypes( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, basePath: IBasePath, config: ObservabilityConfig, logger: Logger, diff --git a/x-pack/plugins/observability_solution/observability/server/plugin.ts b/x-pack/plugins/observability_solution/observability/server/plugin.ts index 4d0e809f882e7..53c91feb3b842 100644 --- a/x-pack/plugins/observability_solution/observability/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/server/plugin.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginSetupContract, PluginStartContract } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { createUICapabilities as createCasesUICapabilities, getApiTags as getCasesApiTags, @@ -23,21 +23,12 @@ import { LogsExplorerLocatorParams, LOGS_EXPLORER_LOCATOR_ID } from '@kbn/deepli import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; import { i18n } from '@kbn/i18n'; -import { - ApmRuleType, - ES_QUERY_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - SLO_BURN_RATE_RULE_TYPE_ID, - SYNTHETICS_STATUS_RULE, - SYNTHETICS_TLS_RULE, -} from '@kbn/rule-data-utils'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { SharePluginSetup } from '@kbn/share-plugin/server'; import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { ObservabilityConfig } from '.'; import { observabilityFeatureId } from '../common'; @@ -57,13 +48,14 @@ import { registerRoutes } from './routes/register_routes'; import { threshold } from './saved_objects/threshold'; import { AlertDetailsContextualInsightsService } from './services'; import { uiSettings } from './ui_settings'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../common/constants'; import { getCasesFeature } from './features/cases_v1'; import { getCasesFeatureV2 } from './features/cases_v2'; export type ObservabilityPluginSetup = ReturnType; interface PluginSetup { - alerting: PluginSetupContract; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; guidedOnboarding?: GuidedOnboardingPluginSetup; ruleRegistry: RuleRegistryPluginSetupContract; @@ -74,21 +66,17 @@ interface PluginSetup { } interface PluginStart { - alerting: PluginStartContract; + alerting: AlertingServerStart; spaces?: SpacesPluginStart; dataViews: DataViewsServerPluginStart; } -const o11yRuleTypes = [ - SLO_BURN_RATE_RULE_TYPE_ID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ES_QUERY_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - ...Object.values(ApmRuleType), - SYNTHETICS_STATUS_RULE, - SYNTHETICS_TLS_RULE, -]; +const alertingFeatures = OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES.map( + (ruleTypeId) => ({ + ruleTypeId, + consumers: [observabilityFeatureId, ALERTING_FEATURE_ID], + }) +); export class ObservabilityPlugin implements Plugin { private logger: Logger; @@ -141,7 +129,7 @@ export class ObservabilityPlugin implements Plugin { scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], app: [observabilityFeatureId], catalogue: [observabilityFeatureId], - alerting: o11yRuleTypes, + alerting: alertingFeatures, privileges: { all: { app: [observabilityFeatureId], @@ -153,10 +141,10 @@ export class ObservabilityPlugin implements Plugin { }, alerting: { rule: { - all: o11yRuleTypes, + all: alertingFeatures, }, alert: { - all: o11yRuleTypes, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -171,10 +159,10 @@ export class ObservabilityPlugin implements Plugin { }, alerting: { rule: { - read: o11yRuleTypes, + read: alertingFeatures, }, alert: { - read: o11yRuleTypes, + read: alertingFeatures, }, }, ui: ['read'], diff --git a/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts b/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts index f5c6c393371c5..7b224dc92ade4 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts @@ -12,9 +12,13 @@ import { createObservabilityServerRoute } from '../create_observability_server_r const getObservabilityAlertDetailsContextRoute = createObservabilityServerRoute({ endpoint: 'GET /internal/observability/assistant/alert_details_contextual_insights', options: { - tags: [], access: 'internal', }, + security: { + authz: { + requiredPrivileges: ['ai_assistant'], + }, + }, params: t.type({ query: alertDetailsContextRt, }), diff --git a/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts index 9ce2d7c9f1829..e10ce506bc99a 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts @@ -30,7 +30,7 @@ export interface RegisterRoutesDependencies { assistant: { alertDetailsContextualInsightsService: AlertDetailsContextualInsightsService; }; - getRulesClientWithRequest: (request: KibanaRequest) => RulesClientApi; + getRulesClientWithRequest: (request: KibanaRequest) => Promise; } export function registerRoutes({ repository, core, logger, dependencies }: RegisterRoutes) { diff --git a/x-pack/plugins/observability_solution/observability/server/routes/types.ts b/x-pack/plugins/observability_solution/observability/server/routes/types.ts index 111bc4e714119..1b189e1233b49 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/types.ts @@ -24,7 +24,7 @@ export interface ObservabilityRouteHandlerResources { } export interface ObservabilityRouteCreateOptions { - tags: string[]; + tags?: string[]; access?: 'public' | 'internal'; } diff --git a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts index 1a387f24fbaed..e5695a3c9034d 100644 --- a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts @@ -504,7 +504,7 @@ export const uiSettings: Record = { value: 1.7, description: i18n.translate('xpack.observability.profilingDatacenterPUEUiSettingDescription', { defaultMessage: `Data center power usage effectiveness (PUE) measures how efficiently a data center uses energy. Defaults to 1.7, the average on-premise data center PUE according to the Uptime Institute survey - + You can also use the PUE that corresponds with your cloud provider: '
        • AWS: 1.135
        • @@ -622,8 +622,8 @@ export const uiSettings: Record = { description: i18n.translate( 'xpack.observability.advancedSettings.searchExcludedDataTiersDesc', { - defaultMessage: `{technicalPreviewLabel} Specify the data tiers to exclude from search, such as data_cold and/or data_frozen. - When configured, indices allocated in the selected tiers will be ignored from search requests. Affected apps: APM`, + defaultMessage: `{technicalPreviewLabel} Specify the data tiers to exclude from search, such as data_cold and/or data_frozen. + When configured, indices allocated in the selected tiers will be ignored from search requests. Affected apps: APM, Infrastructure`, values: { technicalPreviewLabel: `[${technicalPreviewLabel}]` }, } ), diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index b3c18dc24b8e0..1d88901626da2 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -111,7 +111,8 @@ "@kbn/core-ui-settings-server-mocks", "@kbn/es-types", "@kbn/logging-mocks", - "@kbn/streams-plugin", + "@kbn/response-ops-rule-form", + "@kbn/streams-plugin" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts index 049c5a1e65fb0..422ef625cdc64 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts @@ -10,10 +10,16 @@ import { AssistantScope } from '@kbn/ai-assistant-common'; import type { Message } from '../../common'; import { chatFeedbackEventSchema, ChatFeedback } from './schemas/chat_feedback'; import { insightFeedbackEventSchema, InsightFeedback } from './schemas/insight_feedback'; +import { insightResponseEventSchema, InsightResponse } from './schemas/insight_response'; import { userSentPromptEventSchema } from './schemas/user_sent_prompt'; import { ObservabilityAIAssistantTelemetryEventType } from './telemetry_event_type'; -const schemas = [chatFeedbackEventSchema, insightFeedbackEventSchema, userSentPromptEventSchema]; +const schemas = [ + chatFeedbackEventSchema, + insightFeedbackEventSchema, + userSentPromptEventSchema, + insightResponseEventSchema, +]; export type TelemetryEventTypeWithPayload = | { type: ObservabilityAIAssistantTelemetryEventType.ChatFeedback; payload: ChatFeedback } @@ -21,6 +27,10 @@ export type TelemetryEventTypeWithPayload = | { type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat; payload: Message & { scopes: AssistantScope[] }; + } + | { + type: ObservabilityAIAssistantTelemetryEventType.InsightResponse; + payload: InsightResponse; }; export const registerTelemetryEventTypes = (analytics: AnalyticsServiceSetup) => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.ts new file mode 100644 index 0000000000000..e46eabf7316c0 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.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 type { EventTypeOpts } from '@kbn/core/public'; +import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type'; + +export interface InsightResponse { + '@timestamp': string; +} + +export const insightResponseEventSchema: EventTypeOpts = { + eventType: ObservabilityAIAssistantTelemetryEventType.InsightResponse, + schema: { + '@timestamp': { + type: 'text', + _meta: { + description: 'The timestamp of the last response from the LLM.', + }, + }, + }, +}; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts index e15ae317a7730..17f9c1d53acde 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts @@ -9,4 +9,5 @@ export enum ObservabilityAIAssistantTelemetryEventType { ChatFeedback = 'observability_ai_assistant_chat_feedback', InsightFeedback = 'observability_ai_assistant_insight_feedback', UserSentPromptInChat = 'observability_ai_assistant_user_sent_prompt_in_chat', + InsightResponse = 'observability_ai_assistant_insight_response', } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx index e5168470be8f1..680a92f559f0a 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx @@ -81,6 +81,17 @@ function ChatContent({ next(initialMessagesRef.current); }, [next]); + useEffect(() => { + if (state !== ChatState.Loading && lastAssistantResponse) { + chatService.sendAnalyticsEvent({ + type: ObservabilityAIAssistantTelemetryEventType.InsightResponse, + payload: { + '@timestamp': lastAssistantResponse['@timestamp'], + }, + }); + } + }, [state, lastAssistantResponse, chatService]); + return ( <> ; +let hookResult: RenderHookResult; describe('useChat', () => { beforeEach(() => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts index 7949276ac6aba..b8de2f5688373 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts @@ -134,8 +134,9 @@ export class ObservabilityAIAssistantPlugin core, taskManager: plugins.taskManager, logger: this.logger, - }).catch((error) => { - this.logger.error(`Failed to register migrate knowledge base entries task: ${error}`); + config: this.config, + }).catch((e) => { + this.logger.error(`Knowledge base migration was not successfully: ${e.message}`); }); service.register(registerFunctions); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts index 50ce85e3578e9..37e9248a0c624 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts @@ -133,7 +133,7 @@ const saveKnowledgeBaseUserInstruction = createObservabilityAIAssistantServerRou params: t.type({ body: t.type({ id: t.string, - text: nonEmptyStringRt, + text: t.string, public: toBooleanRt, }), }), diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts index 62365536f3823..645da146dfb89 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts @@ -28,7 +28,7 @@ type ObservabilityAIAssistantRequestHandlerContextBase = CustomRequestHandlerCon // these two are here for compatibility with APM functions rac: Pick; alerting: { - getRulesClient: () => RulesClientApi; + getRulesClient: () => Promise; }; }>; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts index 8da2a0d843b11..f6aa0dfab2726 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { ActionsClient } from '@kbn/actions-plugin/server/actions_client'; -import type { ElasticsearchClient, IUiSettingsClient, Logger } from '@kbn/core/server'; +import type { CoreSetup, ElasticsearchClient, IUiSettingsClient, Logger } from '@kbn/core/server'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import { waitFor } from '@testing-library/react'; import { last, merge, repeat } from 'lodash'; @@ -27,7 +27,9 @@ import { CONTEXT_FUNCTION_NAME } from '../../functions/context'; import { ChatFunctionClient } from '../chat_function_client'; import type { KnowledgeBaseService } from '../knowledge_base_service'; import { observableIntoStream } from '../util/observable_into_stream'; -import { CreateChatCompletionResponseChunk } from './adapters/process_openai_stream'; +import type { CreateChatCompletionResponseChunk } from './adapters/process_openai_stream'; +import type { ObservabilityAIAssistantConfig } from '../../config'; +import type { ObservabilityAIAssistantPluginStartDependencies } from '../../types'; type ChunkDelta = CreateChatCompletionResponseChunk['choices'][number]['delta']; @@ -177,6 +179,8 @@ describe('Observability AI Assistant client', () => { functionClientMock.getAdhocInstructions.mockReturnValue([]); return new ObservabilityAIAssistantClient({ + config: {} as ObservabilityAIAssistantConfig, + core: {} as CoreSetup, actionsClient: actionsClientMock, uiSettingsClient: uiSettingsClientMock, esClient: { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts index 2bd2fdcf22462..107bed3cac7be 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts @@ -7,7 +7,7 @@ import type { SearchHit } from '@elastic/elasticsearch/lib/api/types'; import { notFound } from '@hapi/boom'; import type { ActionsClient } from '@kbn/actions-plugin/server'; -import type { ElasticsearchClient, IUiSettingsClient } from '@kbn/core/server'; +import type { CoreSetup, ElasticsearchClient, IUiSettingsClient } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { SpanKind, context } from '@opentelemetry/api'; @@ -80,13 +80,20 @@ import { LangtraceServiceProvider, withLangtraceChatCompleteSpan, } from './operators/with_langtrace_chat_complete_span'; -import { runSemanticTextKnowledgeBaseMigration } from '../task_manager_definitions/register_migrate_knowledge_base_entries_task'; +import { + runSemanticTextKnowledgeBaseMigration, + scheduleSemanticTextMigration, +} from '../task_manager_definitions/register_migrate_knowledge_base_entries_task'; +import { ObservabilityAIAssistantPluginStartDependencies } from '../../types'; +import { ObservabilityAIAssistantConfig } from '../../config'; const MAX_FUNCTION_CALLS = 8; export class ObservabilityAIAssistantClient { constructor( private readonly dependencies: { + config: ObservabilityAIAssistantConfig; + core: CoreSetup; actionsClient: PublicMethodsOf; uiSettingsClient: IUiSettingsClient; namespace: string; @@ -725,9 +732,23 @@ export class ObservabilityAIAssistantClient { return this.dependencies.knowledgeBaseService.getStatus(); }; - setupKnowledgeBase = (modelId: string | undefined) => { - const { esClient } = this.dependencies; - return this.dependencies.knowledgeBaseService.setup(esClient, modelId); + setupKnowledgeBase = async (modelId: string | undefined) => { + const { esClient, core, logger, knowledgeBaseService } = this.dependencies; + + // setup the knowledge base + const res = await knowledgeBaseService.setup(esClient, modelId); + + core + .getStartServices() + .then(([_, pluginsStart]) => { + logger.debug('Schedule semantic text migration task'); + return scheduleSemanticTextMigration(pluginsStart); + }) + .catch((error) => { + logger.error(`Failed to run semantic text migration task: ${error}`); + }); + + return res; }; resetKnowledgeBase = () => { @@ -739,6 +760,7 @@ export class ObservabilityAIAssistantClient { return runSemanticTextKnowledgeBaseMigration({ esClient: this.dependencies.esClient, logger: this.dependencies.logger, + config: this.dependencies.config, }); }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/with_langtrace_chat_complete_span.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/with_langtrace_chat_complete_span.ts index 9e32ba4b57bfe..767121928622a 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/with_langtrace_chat_complete_span.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/operators/with_langtrace_chat_complete_span.ts @@ -41,7 +41,10 @@ export function withLangtraceChatCompleteSpan({ 'http.max.retries': 0, // dummy URL 'url.full': 'http://localhost:3000/chat/completions', + 'url.path': '/chat/completions', 'http.timeout': 120 * 1000, + 'gen_ai.operation.name': 'chat_completion', + 'gen_ai.request.model': model, 'llm.prompts': JSON.stringify( messages.map((message) => ({ role: message.message.role, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts index 9c26bebdd8388..d98799fcb63a7 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts @@ -5,22 +5,19 @@ * 2.0. */ -import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server/plugin'; -import { createConcreteWriteIndex, getDataStreamAdapter } from '@kbn/alerting-plugin/server'; -import type { CoreSetup, CoreStart, KibanaRequest, Logger } from '@kbn/core/server'; -import type { SecurityPluginStart } from '@kbn/security-plugin/server'; +import type { CoreSetup, KibanaRequest, Logger } from '@kbn/core/server'; import { getSpaceIdFromPath } from '@kbn/spaces-plugin/common'; -import { once } from 'lodash'; import type { AssistantScope } from '@kbn/ai-assistant-common'; +import { once } from 'lodash'; +import pRetry from 'p-retry'; import { ObservabilityAIAssistantScreenContextRequest } from '../../common/types'; import type { ObservabilityAIAssistantPluginStartDependencies } from '../types'; import { ChatFunctionClient } from './chat_function_client'; import { ObservabilityAIAssistantClient } from './client'; -import { conversationComponentTemplate } from './conversation_component_template'; -import { kbComponentTemplate } from './kb_component_template'; import { KnowledgeBaseService } from './knowledge_base_service'; import type { RegistrationCallback, RespondFunctionResources } from './types'; import { ObservabilityAIAssistantConfig } from '../config'; +import { setupConversationAndKbIndexAssets } from './setup_conversation_and_kb_index_assets'; function getResourceName(resource: string) { return `.kibana-observability-ai-assistant-${resource}`; @@ -45,12 +42,15 @@ export const resourceNames = { }, }; +const createIndexAssetsOnce = once( + (logger: Logger, core: CoreSetup) => + pRetry(() => setupConversationAndKbIndexAssets({ logger, core })) +); + export class ObservabilityAIAssistantService { private readonly core: CoreSetup; private readonly logger: Logger; - private kbService?: KnowledgeBaseService; private config: ObservabilityAIAssistantConfig; - private readonly registrations: RegistrationCallback[] = []; constructor({ @@ -65,120 +65,8 @@ export class ObservabilityAIAssistantService { this.core = core; this.logger = logger; this.config = config; - - this.resetInit(); } - init = async () => {}; - - private resetInit = () => { - this.init = once(async () => { - return this.doInit().catch((error) => { - this.resetInit(); // reset the once flag if an error occurs - throw error; - }); - }); - }; - - private doInit = async () => { - try { - this.logger.debug('Setting up index assets'); - const [coreStart] = await this.core.getStartServices(); - - const { asInternalUser } = coreStart.elasticsearch.client; - - await asInternalUser.cluster.putComponentTemplate({ - create: false, - name: resourceNames.componentTemplate.conversations, - template: conversationComponentTemplate, - }); - - await asInternalUser.indices.putIndexTemplate({ - name: resourceNames.indexTemplate.conversations, - composed_of: [resourceNames.componentTemplate.conversations], - create: false, - index_patterns: [resourceNames.indexPatterns.conversations], - template: { - settings: { - number_of_shards: 1, - auto_expand_replicas: '0-1', - hidden: true, - }, - }, - }); - - const conversationAliasName = resourceNames.aliases.conversations; - - await createConcreteWriteIndex({ - esClient: asInternalUser, - logger: this.logger, - totalFieldsLimit: 10000, - indexPatterns: { - alias: conversationAliasName, - pattern: `${conversationAliasName}*`, - basePattern: `${conversationAliasName}*`, - name: `${conversationAliasName}-000001`, - template: resourceNames.indexTemplate.conversations, - }, - dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }), - }); - - // Knowledge base: component template - await asInternalUser.cluster.putComponentTemplate({ - create: false, - name: resourceNames.componentTemplate.kb, - template: kbComponentTemplate, - }); - - // Knowledge base: index template - await asInternalUser.indices.putIndexTemplate({ - name: resourceNames.indexTemplate.kb, - composed_of: [resourceNames.componentTemplate.kb], - create: false, - index_patterns: [resourceNames.indexPatterns.kb], - template: { - settings: { - number_of_shards: 1, - auto_expand_replicas: '0-1', - hidden: true, - }, - }, - }); - - const kbAliasName = resourceNames.aliases.kb; - - // Knowledge base: write index - await createConcreteWriteIndex({ - esClient: asInternalUser, - logger: this.logger, - totalFieldsLimit: 10000, - indexPatterns: { - alias: kbAliasName, - pattern: `${kbAliasName}*`, - basePattern: `${kbAliasName}*`, - name: `${kbAliasName}-000001`, - template: resourceNames.indexTemplate.kb, - }, - dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }), - }); - - this.kbService = new KnowledgeBaseService({ - core: this.core, - logger: this.logger.get('kb'), - config: this.config, - esClient: { - asInternalUser, - }, - }); - - this.logger.info('Successfully set up index assets'); - } catch (error) { - this.logger.error(`Failed setting up index assets: ${error.message}`); - this.logger.debug(error); - throw error; - } - }; - async getClient({ request, scopes, @@ -192,12 +80,11 @@ export class ObservabilityAIAssistantService { controller.abort(); }); - const [_, [coreStart, plugins]] = await Promise.all([ - this.init(), - this.core.getStartServices() as Promise< - [CoreStart, { security: SecurityPluginStart; actions: ActionsPluginStart }, unknown] - >, + const [[coreStart, plugins]] = await Promise.all([ + this.core.getStartServices(), + createIndexAssetsOnce(this.logger, this.core), ]); + // user will not be found when executed from system connector context const user = plugins.security.authc.getCurrentUser(request); @@ -207,12 +94,25 @@ export class ObservabilityAIAssistantService { const { spaceId } = getSpaceIdFromPath(basePath, coreStart.http.basePath.serverBasePath); + const { asInternalUser } = coreStart.elasticsearch.client; + + const kbService = new KnowledgeBaseService({ + core: this.core, + logger: this.logger.get('kb'), + config: this.config, + esClient: { + asInternalUser, + }, + }); + return new ObservabilityAIAssistantClient({ + core: this.core, + config: this.config, actionsClient: await plugins.actions.getActionsClientWithRequest(request), uiSettingsClient: coreStart.uiSettings.asScopedToClient(soClient), namespace: spaceId, esClient: { - asInternalUser: coreStart.elasticsearch.client.asInternalUser, + asInternalUser, asCurrentUser: coreStart.elasticsearch.client.asScoped(request).asCurrentUser, }, logger: this.logger, @@ -222,7 +122,7 @@ export class ObservabilityAIAssistantService { name: user.username, } : undefined, - knowledgeBaseService: this.kbService!, + knowledgeBaseService: kbService, scopes: scopes || ['all'], }); } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/inference_endpoint.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/inference_endpoint.ts index e89028652d9ac..a2993f7353c61 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/inference_endpoint.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/inference_endpoint.ts @@ -9,6 +9,7 @@ import { errors } from '@elastic/elasticsearch'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; import moment from 'moment'; +import { ObservabilityAIAssistantConfig } from '../config'; export const AI_ASSISTANT_KB_INFERENCE_ID = 'obs_ai_assistant_kb_inference'; @@ -34,7 +35,7 @@ export async function createInferenceEndpoint({ service: 'elasticsearch', service_settings: { model_id: modelId, - adaptive_allocations: { enabled: true }, + adaptive_allocations: { enabled: true, min_number_of_allocations: 1 }, num_threads: 1, }, task_settings: {}, @@ -45,7 +46,7 @@ export async function createInferenceEndpoint({ } ); } catch (e) { - logger.error( + logger.debug( `Failed to create inference endpoint "${AI_ASSISTANT_KB_INFERENCE_ID}": ${e.message}` ); throw e; @@ -54,44 +55,30 @@ export async function createInferenceEndpoint({ export async function deleteInferenceEndpoint({ esClient, - logger, }: { esClient: { asCurrentUser: ElasticsearchClient; }; - logger: Logger; }) { - try { - const response = await esClient.asCurrentUser.inference.delete({ - inference_id: AI_ASSISTANT_KB_INFERENCE_ID, - force: true, - }); + const response = await esClient.asCurrentUser.inference.delete({ + inference_id: AI_ASSISTANT_KB_INFERENCE_ID, + force: true, + }); - return response; - } catch (e) { - logger.error(`Failed to delete inference endpoint: ${e.message}`); - throw e; - } + return response; } export async function getInferenceEndpoint({ esClient, - logger, }: { esClient: { asInternalUser: ElasticsearchClient }; - logger: Logger; }) { - try { - const response = await esClient.asInternalUser.inference.get({ - inference_id: AI_ASSISTANT_KB_INFERENCE_ID, - }); + const response = await esClient.asInternalUser.inference.get({ + inference_id: AI_ASSISTANT_KB_INFERENCE_ID, + }); - if (response.endpoints.length > 0) { - return response.endpoints[0]; - } - } catch (e) { - logger.error(`Failed to fetch inference endpoint: ${e.message}`); - throw e; + if (response.endpoints.length > 0) { + return response.endpoints[0]; } } @@ -102,3 +89,61 @@ export function isInferenceEndpointMissingOrUnavailable(error: Error) { error.body?.error?.type === 'status_exception') ); } + +export async function getElserModelStatus({ + esClient, + logger, + config, +}: { + esClient: { asInternalUser: ElasticsearchClient }; + logger: Logger; + config: ObservabilityAIAssistantConfig; +}) { + let errorMessage = ''; + const endpoint = await getInferenceEndpoint({ + esClient, + }).catch((error) => { + if (!isInferenceEndpointMissingOrUnavailable(error)) { + throw error; + } + errorMessage = error.message; + }); + + const enabled = config.enableKnowledgeBase; + if (!endpoint) { + return { ready: false, enabled, errorMessage }; + } + + const modelId = endpoint.service_settings?.model_id; + const modelStats = await esClient.asInternalUser.ml + .getTrainedModelsStats({ model_id: modelId }) + .catch((error) => { + logger.debug(`Failed to get model stats: ${error.message}`); + errorMessage = error.message; + }); + + if (!modelStats) { + return { ready: false, enabled, errorMessage }; + } + + const elserModelStats = modelStats.trained_model_stats.find( + (stats) => stats.deployment_stats?.deployment_id === AI_ASSISTANT_KB_INFERENCE_ID + ); + const deploymentState = elserModelStats?.deployment_stats?.state; + const allocationState = elserModelStats?.deployment_stats?.allocation_status.state; + const allocationCount = + elserModelStats?.deployment_stats?.allocation_status.allocation_count ?? 0; + const ready = + deploymentState === 'started' && allocationState === 'fully_allocated' && allocationCount > 0; + + return { + endpoint, + ready, + enabled, + model_stats: { + allocation_count: allocationCount, + deployment_state: deploymentState, + allocation_state: allocationState, + }, + }; +} diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/kb_component_template.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/kb_component_template.ts index 6cf89b0c9e22d..49e856db29d50 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/kb_component_template.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/kb_component_template.ts @@ -62,10 +62,6 @@ export const kbComponentTemplate: ClusterComponentTemplate['component_template'] semantic_text: { type: 'semantic_text', inference_id: AI_ASSISTANT_KB_INFERENCE_ID, - // @ts-expect-error: @elastic/elasticsearch does not have this type yet - model_settings: { - task_type: 'sparse_embedding', - }, }, 'ml.tokens': { type: 'rank_features', diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts index a98cf6f810f2c..1cf1cdc326fdf 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts @@ -20,10 +20,9 @@ import { import { getAccessQuery } from '../util/get_access_query'; import { getCategoryQuery } from '../util/get_category_query'; import { - AI_ASSISTANT_KB_INFERENCE_ID, createInferenceEndpoint, deleteInferenceEndpoint, - getInferenceEndpoint, + getElserModelStatus, isInferenceEndpointMissingOrUnavailable, } from '../inference_endpoint'; import { recallFromSearchConnectors } from './recall_from_search_connectors'; @@ -61,13 +60,13 @@ export class KnowledgeBaseService { }, modelId: string | undefined ) { - await deleteInferenceEndpoint({ esClient, logger: this.dependencies.logger }).catch((e) => {}); // ensure existing inference endpoint is deleted + await deleteInferenceEndpoint({ esClient }).catch((e) => {}); // ensure existing inference endpoint is deleted return createInferenceEndpoint({ esClient, logger: this.dependencies.logger, modelId }); } async reset(esClient: { asCurrentUser: ElasticsearchClient }) { try { - await deleteInferenceEndpoint({ esClient, logger: this.dependencies.logger }); + await deleteInferenceEndpoint({ esClient }); } catch (error) { if (isInferenceEndpointMissingOrUnavailable(error)) { return; @@ -405,7 +404,7 @@ export class KnowledgeBaseService { document: { '@timestamp': new Date().toISOString(), ...doc, - semantic_text: doc.text, + ...(doc.text ? { semantic_text: doc.text } : {}), user, namespace, }, @@ -437,58 +436,10 @@ export class KnowledgeBaseService { }; getStatus = async () => { - let errorMessage = ''; - const endpoint = await getInferenceEndpoint({ + return getElserModelStatus({ esClient: this.dependencies.esClient, logger: this.dependencies.logger, - }).catch((error) => { - if (!isInferenceEndpointMissingOrUnavailable(error)) { - throw error; - } - this.dependencies.logger.error(`Failed to get inference endpoint: ${error.message}`); - errorMessage = error.message; + config: this.dependencies.config, }); - - const enabled = this.dependencies.config.enableKnowledgeBase; - if (!endpoint) { - return { ready: false, enabled, errorMessage }; - } - - const modelId = endpoint.service_settings?.model_id; - const modelStats = await this.dependencies.esClient.asInternalUser.ml - .getTrainedModelsStats({ model_id: modelId }) - .catch((error) => { - this.dependencies.logger.error(`Failed to get model stats: ${error.message}`); - errorMessage = error.message; - }); - - if (!modelStats) { - return { ready: false, enabled, errorMessage }; - } - - const elserModelStats = modelStats.trained_model_stats.find( - (stats) => stats.deployment_stats?.deployment_id === AI_ASSISTANT_KB_INFERENCE_ID - ); - const deploymentState = elserModelStats?.deployment_stats?.state; - const allocationState = elserModelStats?.deployment_stats?.allocation_status.state; - const allocationCount = - elserModelStats?.deployment_stats?.allocation_status.allocation_count ?? 0; - const ready = - deploymentState === 'started' && allocationState === 'fully_allocated' && allocationCount > 0; - - this.dependencies.logger.debug( - `Model deployment state: ${deploymentState}, allocation state: ${allocationState}, ready: ${ready}` - ); - - return { - endpoint, - ready, - enabled, - model_stats: { - allocation_count: allocationCount, - deployment_state: deploymentState, - allocation_state: allocationState, - }, - }; }; } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/setup_conversation_and_kb_index_assets.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/setup_conversation_and_kb_index_assets.ts new file mode 100644 index 0000000000000..30d55400bbbda --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/setup_conversation_and_kb_index_assets.ts @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createConcreteWriteIndex, getDataStreamAdapter } from '@kbn/alerting-plugin/server'; +import type { CoreSetup, Logger } from '@kbn/core/server'; +import type { ObservabilityAIAssistantPluginStartDependencies } from '../types'; +import { conversationComponentTemplate } from './conversation_component_template'; +import { kbComponentTemplate } from './kb_component_template'; +import { resourceNames } from '.'; + +export async function setupConversationAndKbIndexAssets({ + logger, + core, +}: { + logger: Logger; + core: CoreSetup; +}) { + try { + logger.debug('Setting up index assets'); + const [coreStart] = await core.getStartServices(); + const { asInternalUser } = coreStart.elasticsearch.client; + + // Conversations: component template + await asInternalUser.cluster.putComponentTemplate({ + create: false, + name: resourceNames.componentTemplate.conversations, + template: conversationComponentTemplate, + }); + + // Conversations: index template + await asInternalUser.indices.putIndexTemplate({ + name: resourceNames.indexTemplate.conversations, + composed_of: [resourceNames.componentTemplate.conversations], + create: false, + index_patterns: [resourceNames.indexPatterns.conversations], + template: { + settings: { + number_of_shards: 1, + auto_expand_replicas: '0-1', + hidden: true, + }, + }, + }); + + // Conversations: write index + const conversationAliasName = resourceNames.aliases.conversations; + await createConcreteWriteIndex({ + esClient: asInternalUser, + logger, + totalFieldsLimit: 10000, + indexPatterns: { + alias: conversationAliasName, + pattern: `${conversationAliasName}*`, + basePattern: `${conversationAliasName}*`, + name: `${conversationAliasName}-000001`, + template: resourceNames.indexTemplate.conversations, + }, + dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }), + }); + + // Knowledge base: component template + await asInternalUser.cluster.putComponentTemplate({ + create: false, + name: resourceNames.componentTemplate.kb, + template: kbComponentTemplate, + }); + + // Knowledge base: index template + await asInternalUser.indices.putIndexTemplate({ + name: resourceNames.indexTemplate.kb, + composed_of: [resourceNames.componentTemplate.kb], + create: false, + index_patterns: [resourceNames.indexPatterns.kb], + template: { + settings: { + number_of_shards: 1, + auto_expand_replicas: '0-1', + hidden: true, + }, + }, + }); + + // Knowledge base: write index + const kbAliasName = resourceNames.aliases.kb; + await createConcreteWriteIndex({ + esClient: asInternalUser, + logger, + totalFieldsLimit: 10000, + indexPatterns: { + alias: kbAliasName, + pattern: `${kbAliasName}*`, + basePattern: `${kbAliasName}*`, + name: `${kbAliasName}-000001`, + template: resourceNames.indexTemplate.kb, + }, + dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }), + }); + + logger.info('Successfully set up index assets'); + } catch (error) { + logger.error(`Failed setting up index assets: ${error.message}`); + logger.debug(error); + } +} diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/task_manager_definitions/register_migrate_knowledge_base_entries_task.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/task_manager_definitions/register_migrate_knowledge_base_entries_task.ts index 3df125ab2ba2d..b75074dc7ea54 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/task_manager_definitions/register_migrate_knowledge_base_entries_task.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/task_manager_definitions/register_migrate_knowledge_base_entries_task.ts @@ -12,8 +12,10 @@ import type { CoreSetup, Logger } from '@kbn/core/server'; import pRetry from 'p-retry'; import { KnowledgeBaseEntry } from '../../../common'; import { resourceNames } from '..'; -import { getInferenceEndpoint } from '../inference_endpoint'; +import { getElserModelStatus } from '../inference_endpoint'; import { ObservabilityAIAssistantPluginStartDependencies } from '../../types'; +import { ObservabilityAIAssistantConfig } from '../../config'; +import { setupConversationAndKbIndexAssets } from '../setup_conversation_and_kb_index_assets'; const TASK_ID = 'obs-ai-assistant:knowledge-base-migration-task-id'; const TASK_TYPE = 'obs-ai-assistant:knowledge-base-migration'; @@ -25,36 +27,66 @@ export async function registerMigrateKnowledgeBaseEntriesTask({ taskManager, logger, core, + config, }: { taskManager: TaskManagerSetupContract; logger: Logger; core: CoreSetup; + config: ObservabilityAIAssistantConfig; }) { - logger.debug(`Register task "${TASK_TYPE}"`); - const [coreStart, pluginsStart] = await core.getStartServices(); - taskManager.registerTaskDefinitions({ - [TASK_TYPE]: { - title: 'Migrate AI Assistant Knowledge Base', - description: `Migrates AI Assistant knowledge base entries`, - timeout: '1h', - maxAttempts: 5, - createTaskRunner() { - return { - async run() { - logger.debug(`Run task: "${TASK_TYPE}"`); - - const esClient = { asInternalUser: coreStart.elasticsearch.client.asInternalUser }; - await runSemanticTextKnowledgeBaseMigration({ esClient, logger }); - }, - }; + try { + logger.debug(`Register task "${TASK_TYPE}"`); + taskManager.registerTaskDefinitions({ + [TASK_TYPE]: { + title: 'Migrate AI Assistant Knowledge Base', + description: `Migrates AI Assistant knowledge base entries`, + timeout: '1h', + maxAttempts: 5, + createTaskRunner() { + return { + async run() { + logger.debug(`Run task: "${TASK_TYPE}"`); + const esClient = coreStart.elasticsearch.client; + + const hasKbIndex = await esClient.asInternalUser.indices.exists({ + index: resourceNames.aliases.kb, + }); + + if (!hasKbIndex) { + logger.debug( + 'Knowledge base index does not exist. Skipping semantic text migration.' + ); + return; + } + + // update fields and mappings + await setupConversationAndKbIndexAssets({ logger, core }); + + // run migration + await runSemanticTextKnowledgeBaseMigration({ esClient, logger, config }); + }, + }; + }, }, - }, - }); + }); + } catch (error) { + logger.error(`Failed to register task "${TASK_TYPE}". Error: ${error}`); + } + + try { + logger.debug(`Scheduled task: "${TASK_TYPE}"`); + await scheduleSemanticTextMigration(pluginsStart); + } catch (error) { + logger.error(`Failed to schedule task "${TASK_TYPE}". Error: ${error}`); + } +} - logger.debug(`Scheduled task: "${TASK_TYPE}"`); - await pluginsStart.taskManager.ensureScheduled({ +export function scheduleSemanticTextMigration( + pluginsStart: ObservabilityAIAssistantPluginStartDependencies +) { + return pluginsStart.taskManager.ensureScheduled({ id: TASK_ID, taskType: TASK_TYPE, scope: ['aiAssistant'], @@ -66,9 +98,11 @@ export async function registerMigrateKnowledgeBaseEntriesTask({ export async function runSemanticTextKnowledgeBaseMigration({ esClient, logger, + config, }: { esClient: { asInternalUser: ElasticsearchClient }; logger: Logger; + config: ObservabilityAIAssistantConfig; }) { logger.debug('Knowledge base migration: Running migration'); @@ -98,7 +132,7 @@ export async function runSemanticTextKnowledgeBaseMigration({ logger.debug(`Knowledge base migration: Found ${response.hits.hits.length} entries to migrate`); - await waitForInferenceEndpoint({ esClient, logger }); + await waitForModel({ esClient, logger, config }); // Limit the number of concurrent requests to avoid overloading the cluster const limiter = pLimit(10); @@ -109,6 +143,7 @@ export async function runSemanticTextKnowledgeBaseMigration({ } return esClient.asInternalUser.update({ + refresh: 'wait_for', index: resourceNames.aliases.kb, id: hit._id, body: { @@ -123,27 +158,29 @@ export async function runSemanticTextKnowledgeBaseMigration({ await Promise.all(promises); logger.debug(`Knowledge base migration: Migrated ${promises.length} entries`); - await runSemanticTextKnowledgeBaseMigration({ esClient, logger }); + await runSemanticTextKnowledgeBaseMigration({ esClient, logger, config }); } catch (e) { - logger.error('Knowledge base migration: Failed to migrate entries'); - logger.error(e); + logger.error(`Knowledge base migration failed: ${e.message}`); } } -async function waitForInferenceEndpoint({ +async function waitForModel({ esClient, logger, + config, }: { esClient: { asInternalUser: ElasticsearchClient }; logger: Logger; + config: ObservabilityAIAssistantConfig; }) { return pRetry( async () => { - const endpoint = await getInferenceEndpoint({ esClient, logger }); - if (!endpoint) { - throw new Error('Inference endpoint not yet ready'); + const { ready } = await getElserModelStatus({ esClient, logger, config }); + if (!ready) { + logger.debug('Elser model is not yet ready. Retrying...'); + throw new Error('Elser model is not yet ready'); } }, - { retries: 20, factor: 2 } + { retries: 30, factor: 2, maxTimeout: 30_000 } ); } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/eventsource_stream_into_observable.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/eventsource_stream_into_observable.ts index 5ff332128f8ac..b2426d8e4eb5d 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/eventsource_stream_into_observable.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/util/eventsource_stream_into_observable.ts @@ -14,10 +14,10 @@ import { Observable } from 'rxjs'; export function eventsourceStreamIntoObservable(readable: Readable) { return new Observable((subscriber) => { - const parser = createParser((event) => { - if (event.type === 'event') { + const parser = createParser({ + onEvent: (event) => { subscriber.next(event.data); - } + }, }); async function processStream() { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts index a8ab57b8ee53c..f44911c172ce4 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts @@ -22,10 +22,7 @@ import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing- import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; -import type { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { ObservabilityAIAssistantService } from './service'; export interface ObservabilityAIAssistantServerSetup { @@ -51,7 +48,7 @@ export interface ObservabilityAIAssistantPluginSetupDependencies { licensing: LicensingPluginSetup; cloud?: CloudSetup; serverless?: ServerlessPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; } export interface ObservabilityAIAssistantPluginStartDependencies { @@ -64,5 +61,5 @@ export interface ObservabilityAIAssistantPluginStartDependencies { ruleRegistry: RuleRegistryPluginStartContract; cloud?: CloudStart; serverless?: ServerlessPluginStart; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts index ab1d00392fdb9..ea4ed05e36b66 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useLocalStorage } from './use_local_storage'; describe('useLocalStorage', () => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts index 682f2e2a4b19b..5408dbbf4ab4f 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts @@ -14,8 +14,10 @@ import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE, + AlertConsumers, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { omit } from 'lodash'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '@kbn/observability-plugin/common/constants'; import { FunctionRegistrationParameters } from '.'; const defaultFields = [ @@ -61,15 +63,6 @@ const OMITTED_ALERT_FIELDS = [ 'kibana.version', ] as const; -const DEFAULT_FEATURE_IDS = [ - 'apm', - 'infrastructure', - 'logs', - 'uptime', - 'slo', - 'observability', -] as const; - export function registerAlertsFunction({ functions, resources, @@ -183,7 +176,16 @@ export function registerAlertsFunction({ const kqlQuery = !filter ? [] : [toElasticsearchQuery(fromKueryExpression(filter))]; const response = await alertsClient.find({ - featureIds: DEFAULT_FEATURE_IDS as unknown as string[], + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + consumers: [ + AlertConsumers.APM, + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.LOGS, + AlertConsumers.UPTIME, + AlertConsumers.SLO, + AlertConsumers.OBSERVABILITY, + AlertConsumers.ALERTS, + ], query: { bool: { filter: [ @@ -194,17 +196,17 @@ export function registerAlertsFunction({ lte: end, }, }, - }, - ...kqlQuery, - ...(!includeRecovered - ? [ - { - term: { - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, + ...kqlQuery, + ...(!includeRecovered + ? [ + { + term: { + [ALERT_STATUS]: ALERT_STATUS_ACTIVE, + }, }, - }, - ] - : []), + ] + : []), + }, ], }, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts index a1196be6a829a..0a3fc6d9dc12d 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts @@ -9,10 +9,7 @@ import type { PluginSetupContract as ActionsPluginSetup, PluginStartContract as ActionsPluginStart, } from '@kbn/actions-plugin/server'; -import type { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { DataViewsServerPluginSetup, DataViewsServerPluginStart, @@ -47,7 +44,7 @@ export interface ObservabilityAIAssistantAppServerSetup {} export interface ObservabilityAIAssistantAppPluginStartDependencies { observabilityAIAssistant: ObservabilityAIAssistantServerStart; ruleRegistry: RuleRegistryPluginStartContract; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; licensing: LicensingPluginStart; actions: ActionsPluginStart; security: SecurityPluginStart; @@ -64,7 +61,7 @@ export interface ObservabilityAIAssistantAppPluginStartDependencies { export interface ObservabilityAIAssistantAppPluginSetupDependencies { observabilityAIAssistant: ObservabilityAIAssistantServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; licensing: LicensingPluginSetup; actions: ActionsPluginSetup; security: SecurityPluginSetup; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx index 1c05ca6d52b3f..51801c44a6835 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx @@ -31,7 +31,6 @@ export function KnowledgeBaseEditUserInstructionFlyout({ onClose }: { onClose: ( const { mutateAsync: createEntry, isLoading: isSaving } = useCreateKnowledgeBaseUserInstruction(); const [newEntryText, setNewEntryText] = useState(''); const [newEntryId, setNewEntryId] = useState(); - const isSubmitDisabled = newEntryText.trim() === ''; useEffect(() => { const userInstruction = userInstructions?.find((entry) => !entry.public); @@ -118,7 +117,6 @@ export function KnowledgeBaseEditUserInstructionFlyout({ onClose }: { onClose: ( fill isLoading={isSaving} onClick={handleSubmit} - isDisabled={isSubmitDisabled} > {i18n.translate( 'xpack.observabilityAiAssistantManagement.knowledgeBaseNewManualEntryFlyout.saveButtonLabel', diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/helpers/call_kibana.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/helpers/call_kibana.ts index 879b02f8a93c5..5f36a8a4204f2 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/helpers/call_kibana.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/helpers/call_kibana.ts @@ -24,14 +24,18 @@ export async function callKibana({ ...options, baseURL: baseUrl, auth: { username, password }, - headers: { 'kbn-xsrf': 'true', ...options.headers }, + headers: { 'kbn-xsrf': 'true', 'x-elastic-internal-origin': 'kibana', ...options.headers }, }); return data; } const getBaseUrl = once(async (kibanaHostname: string) => { try { - await axios.request({ url: kibanaHostname, maxRedirects: 0 }); + await axios.request({ + url: kibanaHostname, + maxRedirects: 0, + headers: { 'x-elastic-internal-origin': 'kibana' }, + }); } catch (e) { if (isAxiosError(e)) { const location = e.response?.headers?.location ?? ''; diff --git a/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx b/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx index dcf15d83ef937..f0274ab739b9a 100644 --- a/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx +++ b/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx @@ -14,8 +14,8 @@ import { useProfilingDependencies } from '../profiling_dependencies/use_profilin export const LicenseContext = React.createContext(undefined); -export function LicenseProvider({ children }: { children: React.ReactChild }) { - const { license$ } = useProfilingDependencies().setup.licensing; +export function LicenseProvider({ children }: { children: React.ReactNode }) { + const { license$ } = useProfilingDependencies().start.licensing; const license = useObservable(license$); // if license is not loaded yet, consider it valid const hasInvalidLicense = license?.isActive === false; diff --git a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts index 1c4017a468eae..4bb49fcf8ac55 100644 --- a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts +++ b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts @@ -40,9 +40,9 @@ describe('useCalculateImpactEstimate', () => { it('calculates impact when countExclusive is lower than countInclusive', () => { const calculateImpactEstimates = useCalculateImpactEstimate(); const { selfCPU, totalCPU, totalSamples } = calculateImpactEstimates({ - countExclusive: 500, - countInclusive: 1000, - totalSamples: 10000, + countExclusive: 475, + countInclusive: 950, + totalSamples: 9500, totalSeconds: 15 * 60, // 15m }); @@ -68,9 +68,9 @@ describe('useCalculateImpactEstimate', () => { it('calculates impact', () => { const calculateImpactEstimates = useCalculateImpactEstimate(); const { selfCPU, totalCPU, totalSamples } = calculateImpactEstimates({ - countExclusive: 1000, - countInclusive: 1000, - totalSamples: 10000, + countExclusive: 950, + countInclusive: 950, + totalSamples: 9500, totalSeconds: 15 * 60, // 15m }); diff --git a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts index d148e0cc262dd..a56f8c96d95db 100644 --- a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts +++ b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts @@ -28,7 +28,7 @@ export function useCalculateImpactEstimate() { totalSeconds: number; }) { const annualizedScaleUp = ANNUAL_SECONDS / totalSeconds; - const totalCoreSeconds = totalSamples / 20; + const totalCoreSeconds = totalSamples / 19; const percentage = samples / totalSamples; const coreSeconds = totalCoreSeconds * percentage; const annualizedCoreSeconds = coreSeconds * annualizedScaleUp; diff --git a/x-pack/plugins/observability_solution/profiling/public/types.ts b/x-pack/plugins/observability_solution/profiling/public/types.ts index 89a8f999010ce..31532150cc1fd 100644 --- a/x-pack/plugins/observability_solution/profiling/public/types.ts +++ b/x-pack/plugins/observability_solution/profiling/public/types.ts @@ -18,7 +18,7 @@ import { ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public/plugin'; import { ChartsPluginSetup, ChartsPluginStart } from '@kbn/charts-plugin/public'; -import { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import { ObservabilityAIAssistantPublicSetup, @@ -36,7 +36,6 @@ export interface ProfilingPluginPublicSetupDeps { dataViews: DataViewsPublicPluginSetup; data: DataPublicPluginSetup; charts: ChartsPluginSetup; - licensing: LicensingPluginSetup; share: SharePluginSetup; unifiedSearch: UnifiedSearchPluginSetup; } @@ -50,4 +49,5 @@ export interface ProfilingPluginPublicStartDeps { charts: ChartsPluginStart; share: SharePluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; + licensing: LicensingPluginStart; } diff --git a/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts b/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts index 4d5a7cca0ff7f..7ad001831c0e4 100644 --- a/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts +++ b/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts @@ -52,7 +52,9 @@ export function registerTopNFunctionsAPMTransactionsRoute({ }); } const core = await context.core; - const { transaction: transactionIndices } = await apmDataAccess.getApmIndices(); + const { transaction: transactionIndices } = await apmDataAccess.getApmIndices( + core.savedObjects.client + ); const esClient = await getClient(context); diff --git a/x-pack/plugins/observability_solution/slo/README.md b/x-pack/plugins/observability_solution/slo/README.md index f577b2da35ec9..df6872a5e9ec8 100755 --- a/x-pack/plugins/observability_solution/slo/README.md +++ b/x-pack/plugins/observability_solution/slo/README.md @@ -20,3 +20,27 @@ See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/
          yarn plugin-helpers dev --watch
          Execute this to build your plugin ui browser side so Kibana could pick up when started in development
          + + +## API Integration Tests +The SLO tests are located under `x-pack/test/api_integration/deployment_agnostic/apis/observability/slo` folder. In order to run the SLO tests of your interest, you can grep accordingly. Use the commands below to run all SLO tests (`grep=SLO`) on stateful or serverless. + +### Stateful + +``` +# start server +node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts + +# run tests +node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep=SLO +``` + +### Serverless + +``` +# start server +node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts + +# run tests +node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep=SLO +``` diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json index b4d66229dc495..915fa9e108d4a 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json @@ -14,8 +14,12 @@ }, "servers": [ { - "url": "http://localhost:5601", - "description": "local" + "url": "https://{kibana_url}", + "variables": { + "kibana_url": { + "default": "localhost:5601" + } + } } ], "tags": [ @@ -102,12 +106,7 @@ } } } - }, - "servers": [ - { - "url": "https://localhost:5601" - } - ] + } }, "get": { "summary": "Get a paginated list of SLOs", @@ -738,12 +737,7 @@ } } } - }, - "servers": [ - { - "url": "https://localhost:5601" - } - ] + } } } }, @@ -1653,20 +1647,25 @@ "description": "Defines properties for SLO settings.", "type": "object", "properties": { + "syncField": { + "description": "The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field.", + "type": "string", + "example": "event.ingested" + }, "syncDelay": { - "description": "The synch delay to apply to the transform. Default 1m", + "description": "The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval.", "type": "string", "default": "1m", "example": "5m" }, "frequency": { - "description": "Configure how often the transform runs, default 1m", + "description": "The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute.", "type": "string", "default": "1m", "example": "5m" }, "preventInitialBackfill": { - "description": "Prevents the transform from backfilling data when it starts.", + "description": "Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window.", "type": "boolean", "default": false, "example": true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml index fde29b3602be0..96d63163b1d51 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml @@ -9,8 +9,10 @@ info: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license servers: - - url: http://localhost:5601 - description: local + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives @@ -63,8 +65,6 @@ paths: application/json: schema: $ref: '#/components/schemas/409_response' - servers: - - url: https://localhost:5601 get: summary: Get a paginated list of SLOs operationId: findSlosOp @@ -448,8 +448,6 @@ paths: application/json: schema: $ref: '#/components/schemas/403_response' - servers: - - url: https://localhost:5601 components: parameters: kbn_xsrf: @@ -1139,18 +1137,22 @@ components: description: Defines properties for SLO settings. type: object properties: + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + type: string + example: event.ingested syncDelay: - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. type: string default: 1m example: 5m frequency: - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. type: string default: 1m example: 5m preventInitialBackfill: - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. type: boolean default: false example: true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml index a50ce0c28c136..e811e18734d51 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml @@ -2,18 +2,22 @@ title: Settings description: Defines properties for SLO settings. type: object properties: + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + type: string + example: 'event.ingested' syncDelay: - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. type: string default: 1m example: 5m frequency: - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. type: string default: 1m example: 5m preventInitialBackfill: - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. type: boolean default: false example: true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml index a1f7a8739c07c..413540ecb96c6 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml @@ -12,8 +12,10 @@ tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives servers: - - url: "http://localhost:5601" - description: local + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 paths: "/s/{spaceId}/api/observability/slos": $ref: "paths/s@{spaceid}@api@slos.yaml" @@ -31,17 +33,3 @@ paths: # $ref: "paths/s@{spaceid}@api@slos@_definitions.yaml" "/s/{spaceId}/api/observability/slos/_delete_instances": $ref: "paths/s@{spaceid}@api@slos@_delete_instances.yaml" -# Security is defined when files are joined in oas_docs -# components: -# securitySchemes: -# basicAuth: -# type: http -# scheme: basic -# apiKeyAuth: -# type: apiKey -# in: header -# name: Authorization -# description: 'e.g. Authorization: ApiKey base64AccessApiKey' -# security: -# - basicAuth: [] -# - apiKeyAuth: [] diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml index ed489df00d800..68de4d633a820 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml @@ -46,9 +46,6 @@ post: application/json: schema: $ref: '../components/schemas/409_response.yaml' - servers: - - url: https://localhost:5601 - get: summary: Get a paginated list of SLOs operationId: findSlosOp diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml index 3ae6388f09d59..f7d0e3a3c884c 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml @@ -37,5 +37,3 @@ post: application/json: schema: $ref: '../components/schemas/403_response.yaml' - servers: - - url: https://localhost:5601 diff --git a/x-pack/plugins/observability_solution/slo/kibana.jsonc b/x-pack/plugins/observability_solution/slo/kibana.jsonc index 11eca10c6c8db..1a90f45c8cd9b 100644 --- a/x-pack/plugins/observability_solution/slo/kibana.jsonc +++ b/x-pack/plugins/observability_solution/slo/kibana.jsonc @@ -44,10 +44,11 @@ "optionalPlugins": [ "cloud", "discover", + "embeddableEnhanced", "observabilityAIAssistant", + "security", "serverless", - "spaces", - "security" + "spaces" ], "requiredBundles": [ "controls", diff --git a/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts b/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts index ce50190eb7adf..0fccc4deb0f8b 100644 --- a/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts +++ b/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts @@ -39,6 +39,7 @@ const baseSlo: Omit = { good: 'http_status: 2xx', total: 'a query', timestampField: 'custom_timestamp', + dataViewId: 'some-data-view-id', }, }, timeWindow: { diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 968d1f80a0824..9aea7b17f43f1 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -9,7 +9,7 @@ import type { TimeRange } from '@kbn/es-query'; import { useTimeBuckets } from '@kbn/observability-plugin/public'; import { getAlertSummaryTimeRange } from '@kbn/observability-plugin/public'; import { calculateTimeRangeBucketSize } from '@kbn/observability-plugin/public'; -import { observabilityAlertFeatureIds } from '@kbn/observability-plugin/common'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useSloAlertsQuery } from './slo_alerts_table'; import { SloEmbeddableDeps } from '../types'; @@ -61,7 +61,8 @@ export function SloAlertsSummary({ return ( { - const factory: ReactEmbeddableFactory< - SloOverviewEmbeddableState, - SloOverviewEmbeddableState, - SloOverviewApi - > = { - type: SLO_OVERVIEW_EMBEDDABLE_ID, - deserializeState: (state) => { - return state.rawState as SloOverviewEmbeddableState; - }, - buildEmbeddable: async (state, buildApi, uuid, parentApi) => { - const deps = { ...coreStart, ...pluginsStart }; - async function onEdit() { - try { - const { openSloConfiguration } = await import('./slo_overview_open_configuration'); +}): ReactEmbeddableFactory< + SloOverviewEmbeddableState, + SloOverviewEmbeddableState, + SloOverviewApi +> => ({ + type: SLO_OVERVIEW_EMBEDDABLE_ID, + deserializeState: (state) => { + return state.rawState as SloOverviewEmbeddableState; + }, + buildEmbeddable: async (state, buildApi, uuid, parentApi) => { + const deps = { ...coreStart, ...pluginsStart }; - const result = await openSloConfiguration( - coreStart, - pluginsStart, - sloClient, - api.getSloGroupOverviewConfig() - ); - api.updateSloGroupOverviewConfig(result as GroupSloCustomInput); - } catch (e) { - return Promise.reject(); - } - } - const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); - const defaultTitle$ = new BehaviorSubject(getOverviewPanelTitle()); - const sloId$ = new BehaviorSubject(state.sloId); - const sloInstanceId$ = new BehaviorSubject(state.sloInstanceId); - const showAllGroupByInstances$ = new BehaviorSubject(state.showAllGroupByInstances); - const overviewMode$ = new BehaviorSubject(state.overviewMode); - const groupFilters$ = new BehaviorSubject(state.groupFilters); - const remoteName$ = new BehaviorSubject(state.remoteName); - const reload$ = new Subject(); + const dynamicActionsApi = deps.embeddableEnhanced?.initializeReactEmbeddableDynamicActions( + uuid, + () => titlesApi.panelTitle.getValue(), + state + ); - const api = buildApi( - { - ...titlesApi, - defaultPanelTitle: defaultTitle$, - getTypeDisplayName: () => - i18n.translate('xpack.slo.editSloOverviewEmbeddableTitle.typeDisplayName', { - defaultMessage: 'criteria', - }), - isEditingEnabled: () => api.getSloGroupOverviewConfig().overviewMode === 'groups', - onEdit: async () => { - onEdit(); - }, - serializeState: () => { - return { - rawState: { - ...serializeTitles(), - sloId: sloId$.getValue(), - sloInstanceId: sloInstanceId$.getValue(), - showAllGroupByInstances: showAllGroupByInstances$.getValue(), - overviewMode: overviewMode$.getValue(), - groupFilters: groupFilters$.getValue(), - remoteName: remoteName$.getValue(), - }, - }; - }, - getSloGroupOverviewConfig: () => { - return { - groupFilters: groupFilters$.getValue(), + const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); + + const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); + const defaultTitle$ = new BehaviorSubject(getOverviewPanelTitle()); + const sloId$ = new BehaviorSubject(state.sloId); + const sloInstanceId$ = new BehaviorSubject(state.sloInstanceId); + const showAllGroupByInstances$ = new BehaviorSubject(state.showAllGroupByInstances); + const overviewMode$ = new BehaviorSubject(state.overviewMode); + const groupFilters$ = new BehaviorSubject(state.groupFilters); + const remoteName$ = new BehaviorSubject(state.remoteName); + const reload$ = new Subject(); + + const api = buildApi( + { + ...titlesApi, + ...(dynamicActionsApi?.dynamicActionsApi ?? {}), + supportedTriggers: () => [], + defaultPanelTitle: defaultTitle$, + getTypeDisplayName: () => + i18n.translate('xpack.slo.editSloOverviewEmbeddableTitle.typeDisplayName', { + defaultMessage: 'criteria', + }), + isEditingEnabled: () => api.getSloGroupOverviewConfig().overviewMode === 'groups', + onEdit: async function onEdit() { + try { + const { openSloConfiguration } = await import('./slo_overview_open_configuration'); + + const result = await openSloConfiguration( + coreStart, + pluginsStart, + sloClient, + api.getSloGroupOverviewConfig() + ); + api.updateSloGroupOverviewConfig(result as GroupSloCustomInput); + } catch (e) { + return Promise.reject(); + } + }, + serializeState: () => { + return { + rawState: { + ...serializeTitles(), + sloId: sloId$.getValue(), + sloInstanceId: sloInstanceId$.getValue(), + showAllGroupByInstances: showAllGroupByInstances$.getValue(), overviewMode: overviewMode$.getValue(), - }; - }, - updateSloGroupOverviewConfig: (update: GroupSloCustomInput) => { - groupFilters$.next(update.groupFilters); - }, + groupFilters: groupFilters$.getValue(), + remoteName: remoteName$.getValue(), + ...(dynamicActionsApi?.serializeDynamicActions?.() ?? {}), + }, + }; }, - { - sloId: [sloId$, (value) => sloId$.next(value)], - sloInstanceId: [sloInstanceId$, (value) => sloInstanceId$.next(value)], - groupFilters: [groupFilters$, (value) => groupFilters$.next(value)], - showAllGroupByInstances: [ - showAllGroupByInstances$, - (value) => showAllGroupByInstances$.next(value), - ], - remoteName: [remoteName$, (value) => remoteName$.next(value)], - overviewMode: [overviewMode$, (value) => overviewMode$.next(value)], - ...titleComparators, - } - ); - - const fetchSubscription = fetch$(api) - .pipe() - .subscribe((next) => { - reload$.next(next.isReload); - }); + getSloGroupOverviewConfig: () => { + return { + groupFilters: groupFilters$.getValue(), + overviewMode: overviewMode$.getValue(), + }; + }, + updateSloGroupOverviewConfig: (update: GroupSloCustomInput) => { + groupFilters$.next(update.groupFilters); + }, + }, + { + sloId: [sloId$, (value) => sloId$.next(value)], + sloInstanceId: [sloInstanceId$, (value) => sloInstanceId$.next(value)], + groupFilters: [groupFilters$, (value) => groupFilters$.next(value)], + showAllGroupByInstances: [ + showAllGroupByInstances$, + (value) => showAllGroupByInstances$.next(value), + ], + remoteName: [remoteName$, (value) => remoteName$.next(value)], + overviewMode: [overviewMode$, (value) => overviewMode$.next(value)], + ...titleComparators, + ...(dynamicActionsApi?.dynamicActionsComparator ?? { + enhancements: getUnchangingComparator(), + }), + } + ); - return { - api, - Component: () => { - const [ - sloId, - sloInstanceId, - showAllGroupByInstances, - overviewMode, - groupFilters, - remoteName, - ] = useBatchedPublishingSubjects( - sloId$, - sloInstanceId$, - showAllGroupByInstances$, - overviewMode$, - groupFilters$, - remoteName$ - ); + const fetchSubscription = fetch$(api) + .pipe() + .subscribe((next) => { + reload$.next(next.isReload); + }); - useEffect(() => { - return () => { - fetchSubscription.unsubscribe(); - }; - }, []); - const renderOverview = () => { - if (overviewMode === 'groups') { - const groupBy = groupFilters?.groupBy ?? 'status'; - const kqlQuery = groupFilters?.kqlQuery ?? ''; - const groups = groupFilters?.groups ?? []; - return ( -
          css` - width: 100%; - padding: ${euiTheme.size.xs} ${euiTheme.size.base}; - overflow: scroll; + return { + api, + Component: () => { + const [ + sloId, + sloInstanceId, + showAllGroupByInstances, + overviewMode, + groupFilters, + remoteName, + ] = useBatchedPublishingSubjects( + sloId$, + sloInstanceId$, + showAllGroupByInstances$, + overviewMode$, + groupFilters$, + remoteName$ + ); - .euiAccordion__buttonContent { - min-width: ${euiTheme.base * 6}px; - } - `} - > - - css` - margin-top: ${euiTheme.base * 1.25}px; - `} - > - - - -
          - ); - } else { - return ( - - ); - } + useEffect(() => { + return () => { + fetchSubscription.unsubscribe(); + maybeStopDynamicActions?.stopDynamicActions(); }; + }, []); + const renderOverview = () => { + if (overviewMode === 'groups') { + const groupBy = groupFilters?.groupBy ?? 'status'; + const kqlQuery = groupFilters?.kqlQuery ?? ''; + const groups = groupFilters?.groups ?? []; + return ( +
          css` + width: 100%; + padding: ${euiTheme.size.xs} ${euiTheme.size.base}; + overflow: scroll; - const queryClient = new QueryClient(); - - return ( - - - - + + css` + margin-top: ${euiTheme.base * 1.25}px; + `} > - - {showAllGroupByInstances ? ( - - ) : ( - renderOverview() - )} - - - - - - ); - }, - }; - }, - }; - return factory; -}; + + + +
          + ); + } else { + return ( + + ); + } + }; + + const queryClient = new QueryClient(); + + return ( + + + + + + {showAllGroupByInstances ? ( + + ) : ( + renderOverview() + )} + + + + + + ); + }, + }; + }, +}); diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts index 3c2866077aaa6..d79a0ecd8a4dc 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts @@ -4,15 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin'; +import { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; +import { Filter } from '@kbn/es-query'; +import type { EmbeddableApiContext, HasSupportedTriggers } from '@kbn/presentation-publishing'; import { - SerializedTitles, - PublishesWritablePanelTitle, - PublishesPanelTitle, HasEditCapabilities, + PublishesPanelTitle, + PublishesWritablePanelTitle, + SerializedTitles, } from '@kbn/presentation-publishing'; -import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; -import { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; -import { Filter } from '@kbn/es-query'; export type OverviewMode = 'single' | 'groups'; export type GroupBy = 'slo.tags' | 'status' | 'slo.indicator.type'; @@ -39,6 +40,7 @@ export type GroupSloCustomInput = SloConfigurationProps & { }; export type SloOverviewEmbeddableState = SerializedTitles & + Partial & Partial & Partial; @@ -46,7 +48,8 @@ export type SloOverviewApi = DefaultEmbeddableApi & PublishesWritablePanelTitle & PublishesPanelTitle & HasSloGroupOverviewConfig & - HasEditCapabilities; + HasEditCapabilities & + HasSupportedTriggers; export interface HasSloGroupOverviewConfig { getSloGroupOverviewConfig: () => GroupSloCustomInput; diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts index 8fa7d3ec88e91..8ca275ae78a1a 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts @@ -8,7 +8,10 @@ import { useQuery } from '@tanstack/react-query'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { + AlertConsumers, + SLO_RULE_TYPE_IDS, +} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; import { ActiveAlerts } from './active_alerts'; @@ -57,7 +60,8 @@ export function useFetchActiveAlerts({ try { const response = await http.post(`${BASE_RAC_ALERTS_API_PATH}/find`, { body: JSON.stringify({ - feature_ids: [AlertConsumers.SLO, AlertConsumers.OBSERVABILITY], + rule_type_ids: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.OBSERVABILITY, AlertConsumers.ALERTS], size: 0, query: { bool: { @@ -69,11 +73,6 @@ export function useFetchActiveAlerts({ }, }, }, - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, { term: { 'kibana.alert.status': 'active', diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts index ce1efab910723..65546a3f6c96c 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts @@ -12,8 +12,9 @@ import { useQuery, } from '@tanstack/react-query'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; -import { BASE_ALERTING_API_PATH } from '@kbn/alerting-plugin/common'; +import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common'; import { HttpSetup } from '@kbn/core/public'; +import { SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; import { WindowSchema } from '../typings'; @@ -54,17 +55,15 @@ async function fetchRules({ http: HttpSetup; signal?: AbortSignal; }) { - const filter = 'alert.attributes.alertTypeId:slo.rules.burnRate'; - - const query = { + const body = { search, - filter, fields: ['id', 'params.windows', 'name'], per_page: 1000, + rule_type_ids: SLO_RULE_TYPE_IDS, }; - const response = await http.get(`${BASE_ALERTING_API_PATH}/rules/_find`, { - query, + const response = await http.post(INTERNAL_ALERTING_API_FIND_RULES_PATH, { + body: JSON.stringify({ ...body }), signal, }); diff --git a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts index 40fcae8c840ee..55305a4a3719b 100644 --- a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts @@ -11,16 +11,21 @@ import { SloEditLocatorDefinition } from './slo_edit'; describe('SloEditLocator', () => { const locator = new SloEditLocatorDefinition(); - it('should return correct url when empty params are provided', async () => { + it('returns the correct url when empty params are provided', async () => { const location = await locator.getLocation({}); expect(location.app).toEqual('slo'); expect(location.path).toEqual('/create?_a=()'); }); - it('should return correct url when slo is provided', async () => { - const location = await locator.getLocation(buildSlo({ id: 'foo' })); + it('returns the correct url when slo id is provided', async () => { + const location = await locator.getLocation({ id: 'existing-slo-id' }); + expect(location.path).toEqual('/edit/existing-slo-id'); + }); + + it('returns the correct url when partial slo input is provided', async () => { + const location = await locator.getLocation(buildSlo({ id: undefined })); expect(location.path).toEqual( - "/edit/foo?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',groupings:(),id:foo,indicator:(params:(filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',meta:(),name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',preventInitialBackfill:!f,syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z',version:2)" + "/create?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',meta:(),name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',preventInitialBackfill:!f,syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z',version:2)" ); }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts index 120bc533e9eea..2233ea9c5718b 100644 --- a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts +++ b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts @@ -5,31 +5,34 @@ * 2.0. */ -import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import type { RecursivePartial } from '@elastic/charts'; -import type { SerializableRecord } from '@kbn/utility-types'; -import type { LocatorDefinition } from '@kbn/share-plugin/public'; +import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { sloEditLocatorID } from '@kbn/observability-plugin/common'; -import type { CreateSLOForm } from '../pages/slo_edit/types'; +import type { LocatorDefinition } from '@kbn/share-plugin/public'; +import { CreateSLOInput } from '@kbn/slo-schema'; import { SLO_CREATE_PATH } from '../../common/locators/paths'; -export type SloEditParams = RecursivePartial; - -export interface SloEditLocatorParams extends SloEditParams, SerializableRecord {} +export type SloEditLocatorParams = RecursivePartial; export class SloEditLocatorDefinition implements LocatorDefinition { public readonly id = sloEditLocatorID; public readonly getLocation = async (slo: SloEditLocatorParams) => { + if (!!slo.id) { + return { + app: 'slo', + path: `/edit/${encodeURIComponent(slo.id)}`, + state: {}, + }; + } + return { app: 'slo', - path: setStateToKbnUrl( + path: setStateToKbnUrl>( '_a', - { - ...slo, - }, + slo, { useHash: false, storeInHashQuery: false }, - slo.id ? `/edit/${encodeURIComponent(String(slo.id))}` : `${SLO_CREATE_PATH}` + SLO_CREATE_PATH ), state: {}, }; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx index 34f3b0132dc8a..9a2f798ab628e 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx @@ -8,15 +8,14 @@ import { EuiFlexGrid, EuiPanel, EuiText, useIsWithinBreakpoints } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; +import { TagsList } from '@kbn/observability-shared-plugin/public'; import { + SLOWithSummaryResponse, occurrencesBudgetingMethodSchema, querySchema, rollingTimeWindowTypeSchema, - SLOWithSummaryResponse, } from '@kbn/slo-schema'; import React from 'react'; -import { TagsList } from '@kbn/observability-shared-plugin/public'; -import { DisplayQuery } from './display_query'; import { useKibana } from '../../../../hooks/use_kibana'; import { BUDGETING_METHOD_OCCURRENCES, @@ -26,9 +25,9 @@ import { toIndicatorTypeLabel, } from '../../../../utils/slo/labels'; import { ApmIndicatorOverview } from './apm_indicator_overview'; -import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview'; - +import { DisplayQuery } from './display_query'; import { OverviewItem } from './overview_item'; +import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview'; export interface Props { slo: SLOWithSummaryResponse; @@ -170,6 +169,19 @@ export function Overview({ slo }: Props) { } /> )} + + + ); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx index 3aa94c00b6441..7b31baf0d62b0 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { Fragment } from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { SLO_ALERTS_TABLE_ID } from '@kbn/observability-shared-plugin/common'; @@ -32,7 +32,8 @@ export function SloDetailsAlerts({ slo }: Props) { configurationId={AlertConsumers.OBSERVABILITY} id={SLO_ALERTS_TABLE_ID} data-test-subj="alertTable" - featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} + ruleTypeIds={SLO_RULE_TYPE_IDS} + consumers={[AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} query={{ bool: { filter: [ diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx new file mode 100644 index 0000000000000..81a630990a256 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiAccordion, + EuiCheckbox, + EuiFieldNumber, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIcon, + EuiIconTip, + EuiTitle, + useGeneratedHtmlId, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import { CreateSLOForm } from '../../../types'; +import { SyncFieldSelector } from './sync_field_selector'; + +export function AdvancedSettings() { + const { control, getFieldState } = useFormContext(); + const preventBackfillCheckbox = useGeneratedHtmlId({ prefix: 'preventBackfill' }); + const advancedSettingsAccordion = useGeneratedHtmlId({ prefix: 'advancedSettingsAccordion' }); + + return ( + + + + + + + +

          + {i18n.translate('xpack.slo.sloEdit.settings.advancedSettingsLabel', { + defaultMessage: 'Advanced settings', + })} +

          +
          +
          + + } + > + + + + + + + + + {i18n.translate('xpack.slo.sloEdit.settings.syncDelay.label', { + defaultMessage: 'Sync delay (in minutes)', + })}{' '} + + + } + > + ( + onChange(event.target.value)} + /> + )} + /> + + + + + + {i18n.translate('xpack.slo.sloEdit.settings.frequency.label', { + defaultMessage: 'Frequency (in minutes)', + })}{' '} + + + } + > + ( + onChange(event.target.value)} + /> + )} + /> + + + + + + ( + + {i18n.translate('xpack.slo.sloEdit.settings.preventInitialBackfill.label', { + defaultMessage: 'Prevent initial backfill of data', + })}{' '} + + + } + checked={Boolean(field.value)} + onChange={(event: any) => onChange(event.target.checked)} + /> + )} + /> + + +
          + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx new file mode 100644 index 0000000000000..ddfb51bb28977 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiIconTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { createOptionsFromFields } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { OptionalText } from '../../common/optional_text'; + +const placeholder = i18n.translate('xpack.slo.sloEdit.settings.syncField.placeholder', { + defaultMessage: 'Select a timestamp field', +}); + +export function SyncFieldSelector() { + const { control, watch, getFieldState } = useFormContext(); + const [index, dataViewId] = watch(['indicator.params.index', 'indicator.params.dataViewId']); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: index, + dataViewId, + }); + const timestampFields = dataView?.fields?.filter((field) => field.type === 'date') ?? []; + + return ( + + {i18n.translate('xpack.slo.sloEdit.settings.syncField.label', { + defaultMessage: 'Sync field', + })}{' '} + + + } + isInvalid={getFieldState('settings.syncField').invalid} + labelAppend={} + > + { + return ( + + {...field} + placeholder={placeholder} + aria-label={placeholder} + isClearable + isDisabled={isIndexFieldsLoading} + isInvalid={fieldState.invalid} + isLoading={isIndexFieldsLoading} + onChange={(selected: EuiComboBoxOptionOption[]) => { + if (selected.length) { + return field.onChange(selected[0].value); + } + + field.onChange(null); + }} + singleSelection={{ asPlainText: true }} + options={createOptionsFromFields(timestampFields)} + selectedOptions={ + !!timestampFields && !!field.value + ? [{ value: field.value, label: field.value }] + : [] + } + /> + ); + }} + /> + + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx index c3c506eb484eb..d40d56941ccfe 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { ApmAvailabilityIndicatorTypeForm as Component } from './apm_availability_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx similarity index 88% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx index 0dcddcdb232b5..fd00e3d359530 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx @@ -12,14 +12,14 @@ import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useApmDefaultValues } from '../apm_common/use_apm_default_values'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { GroupByField } from '../common/group_by_field'; -import { useFetchApmIndex } from '../../../../hooks/use_fetch_apm_indices'; -import { CreateSLOForm } from '../../types'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { GroupByField } from '../../common/group_by_field'; +import { useFetchApmIndex } from '../../../../../hooks/use_fetch_apm_indices'; +import { CreateSLOForm } from '../../../types'; import { FieldSelector } from '../apm_common/field_selector'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; -import { formatAllFilters } from '../../helpers/format_filters'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; +import { formatAllFilters } from '../../../helpers/format_filters'; import { getGroupByCardinalityFilters } from '../apm_common/get_group_by_cardinality_filters'; export function ApmAvailabilityIndicatorTypeForm() { @@ -56,8 +56,8 @@ export function ApmAvailabilityIndicatorTypeForm() { }); return ( - - + + - + - + { const { watch, setValue } = useFormContext>(); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx index 3ca02641f9bfa..9b346c94dea9a 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { ApmLatencyIndicatorTypeForm as Component } from './apm_latency_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx index 03b47aafe4150..0d7b86d0b88d3 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx @@ -12,14 +12,14 @@ import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useApmDefaultValues } from '../apm_common/use_apm_default_values'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { useFetchApmIndex } from '../../../../hooks/use_fetch_apm_indices'; -import { CreateSLOForm } from '../../types'; +import { GroupByField } from '../../common/group_by_field'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { useFetchApmIndex } from '../../../../../hooks/use_fetch_apm_indices'; +import { CreateSLOForm } from '../../../types'; import { FieldSelector } from '../apm_common/field_selector'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; -import { formatAllFilters } from '../../helpers/format_filters'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; +import { formatAllFilters } from '../../../helpers/format_filters'; import { getGroupByCardinalityFilters } from '../apm_common/get_group_by_cardinality_filters'; export function ApmLatencyIndicatorTypeForm() { @@ -58,8 +58,8 @@ export function ApmLatencyIndicatorTypeForm() { }); return ( - - + + - + (); const index = watch('indicator.params.index'); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx index 4b8dce62f43bb..b1739a63881f5 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { IndexSelection as Component } from './index_selection'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx similarity index 63% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx index 146d11be84ac8..9d5489ddd283f 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx @@ -8,37 +8,47 @@ import { EuiFormRow } from '@elastic/eui'; import { DataView } from '@kbn/data-views-plugin/public'; import { i18n } from '@kbn/i18n'; +import { ALL_VALUE } from '@kbn/slo-schema'; +import { DataViewPicker } from '@kbn/unified-search-plugin/public'; import React, { useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { DataViewPicker } from '@kbn/unified-search-plugin/public'; -import { getDataViewPattern, useAdhocDataViews } from './use_adhoc_data_views'; -import { SLOPublicPluginsStart } from '../../../..'; -import { useKibana } from '../../../../hooks/use_kibana'; -import { CreateSLOForm } from '../../types'; +import { SLOPublicPluginsStart } from '../../../../..'; +import { useKibana } from '../../../../../hooks/use_kibana'; +import { CreateSLOForm } from '../../../types'; +import { getDataViewPatternOrId, useAdhocDataViews } from './use_adhoc_data_views'; const BTN_MAX_WIDTH = 515; export const DATA_VIEW_FIELD = 'indicator.params.dataViewId'; const INDEX_FIELD = 'indicator.params.index'; -const TIMESTAMP_FIELD = 'indicator.params.timestampField'; +const INDICATOR_TIMESTAMP_FIELD = 'indicator.params.timestampField'; +const GROUP_BY_FIELD = 'groupBy'; +const SETTINGS_SYNC_FIELD = 'settings.syncField'; export function IndexSelection({ selectedDataView }: { selectedDataView?: DataView }) { const { control, getFieldState, setValue, watch } = useFormContext(); - const { dataViews: dataViewsService, dataViewFieldEditor } = useKibana().services; - - const { dataViewEditor } = useKibana().services; + const { + dataViews: dataViewsService, + dataViewFieldEditor, + dataViewEditor, + } = useKibana().services; const currentIndexPattern = watch(INDEX_FIELD); const currentDataViewId = watch(DATA_VIEW_FIELD); - const { dataViewsList, isDataViewsLoading, adHocDataViews, setAdHocDataViews, refetch } = - useAdhocDataViews({ - currentIndexPattern, - }); + const { + dataViewsList, + isDataViewsLoading, + adHocDataViews, + setAdHocDataViews, + refetchDataViewsList, + } = useAdhocDataViews({ + currentIndexPattern, + }); useEffect(() => { - const indPatternId = getDataViewPattern({ - byPatten: currentIndexPattern, + const indPatternId = getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }); @@ -54,13 +64,24 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi setValue, ]); + const updateDataViewDependantFields = (indexPattern?: string, timestampField?: string) => { + setValue(INDEX_FIELD, indexPattern ?? ''); + setValue(INDICATOR_TIMESTAMP_FIELD, timestampField ?? ''); + setValue(GROUP_BY_FIELD, ALL_VALUE); + setValue(SETTINGS_SYNC_FIELD, null); + }; + return ( - + ( { - setValue( - INDEX_FIELD, - getDataViewPattern({ byId: newId, adHocDataViews, dataViewsList })! - ); field.onChange(newId); + dataViewsService.get(newId).then((dataView) => { - if (dataView.timeFieldName) { - setValue(TIMESTAMP_FIELD, dataView.timeFieldName); - } + updateDataViewDependantFields( + getDataViewPatternOrId({ byId: newId, adHocDataViews, dataViewsList })!, + dataView.timeFieldName + ); }); }} onAddField={ @@ -97,8 +116,8 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi } currentDataViewId={ field.value ?? - getDataViewPattern({ - byPatten: currentIndexPattern, + getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }) @@ -108,17 +127,13 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi allowAdHocDataView: true, onSave: (dataView: DataView) => { if (!dataView.isPersisted()) { - setAdHocDataViews([...adHocDataViews, dataView]); - field.onChange(dataView.id); - setValue(INDEX_FIELD, dataView.getIndexPattern()); + setAdHocDataViews((prev) => [...prev, dataView]); } else { - refetch(); - field.onChange(dataView.id); - setValue(INDEX_FIELD, dataView.getIndexPattern()); - } - if (dataView.timeFieldName) { - setValue(TIMESTAMP_FIELD, dataView.timeFieldName); + refetchDataViewsList(); } + + field.onChange(dataView.id); + updateDataViewDependantFields(dataView.getIndexPattern(), dataView.timeFieldName); }, }); }} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts similarity index 79% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts index 67792b056408d..986b681c9bca9 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts @@ -8,16 +8,16 @@ import { useEffect, useState } from 'react'; import { DataView, DataViewListItem } from '@kbn/data-views-plugin/common'; import { useFetchDataViews } from '@kbn/observability-plugin/public'; -import { useKibana } from '../../../../hooks/use_kibana'; +import { useKibana } from '../../../../../hooks/use_kibana'; -export const getDataViewPattern = ({ +export const getDataViewPatternOrId = ({ byId, - byPatten, + byPattern, dataViewsList, adHocDataViews, }: { byId?: string; - byPatten?: string; + byPattern?: string; dataViewsList: DataViewListItem[]; adHocDataViews: DataView[]; }) => { @@ -28,20 +28,24 @@ export const getDataViewPattern = ({ if (byId) { return allDataViews.find((dv) => dv.id === byId)?.title; } - if (byPatten) { - return allDataViews.find((dv) => dv.title === byPatten)?.id; + if (byPattern) { + return allDataViews.find((dv) => dv.title === byPattern)?.id; } }; export const useAdhocDataViews = ({ currentIndexPattern }: { currentIndexPattern: string }) => { - const { isLoading: isDataViewsLoading, data: dataViewsList = [], refetch } = useFetchDataViews(); + const { + isLoading: isDataViewsLoading, + data: dataViewsList = [], + refetch: refetchDataViewsList, + } = useFetchDataViews(); const { dataViews: dataViewsService } = useKibana().services; const [adHocDataViews, setAdHocDataViews] = useState([]); useEffect(() => { if (!isDataViewsLoading) { - const missingDataView = getDataViewPattern({ - byPatten: currentIndexPattern, + const missingDataView = getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }); @@ -70,6 +74,6 @@ export const useAdhocDataViews = ({ currentIndexPattern }: { currentIndexPattern setAdHocDataViews, dataViewsList, isDataViewsLoading, - refetch, + refetchDataViewsList, }; }; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx index 5eb0b68070789..1ecf3f57c1496 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { CustomKqlIndicatorTypeForm as Component } from './custom_kql_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx index 92ba2cac50e7f..ccebca1fbb36f 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx @@ -9,12 +9,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { GroupByField } from '../../common/group_by_field'; +import { QueryBuilder } from '../../common/query_builder'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; export function CustomKqlIndicatorTypeForm() { @@ -28,7 +28,7 @@ export function CustomKqlIndicatorTypeForm() { }); return ( - + diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx similarity index 89% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx index 1abbff61a0dc8..771405a539f1b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { CustomMetricIndicatorTypeForm as Component } from './custom_metric_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx index ee9bcf8d99649..365205ed6b4bf 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx @@ -18,11 +18,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { GroupByField } from '../../common/group_by_field'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { MetricIndicator } from './metric_indicator'; @@ -55,7 +55,7 @@ export function CustomMetricIndicatorTypeForm() { - + diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx similarity index 60% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx index 03939dce314b6..519167be5db27 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx @@ -26,10 +26,10 @@ import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; import { aggValueToLabel, CUSTOM_METRIC_AGGREGATION_OPTIONS, -} from '../../helpers/aggregation_options'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; -import { QueryBuilder } from '../common/query_builder'; +} from '../../../helpers/aggregation_options'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { QueryBuilder } from '../../common/query_builder'; interface MetricIndicatorProps { type: 'good' | 'total'; @@ -134,95 +134,28 @@ export function MetricIndicator({ {fields?.map((metric, index, arr) => (
          - - - - - {i18n.translate('xpack.slo.sloEdit.customMetric.aggregationLabel', { - defaultMessage: 'Aggregation', - })}{' '} - {metric.name} - - } - > - ( - { - if (selected.length) { - return field.onChange(selected[0].value); - } - field.onChange(''); - }} - selectedOptions={ - !!indexPattern && - !!field.value && - CUSTOM_METRIC_AGGREGATION_OPTIONS.some((agg) => agg.value === field.value) - ? [ - { - value: field.value, - label: aggValueToLabel(field.value), - }, - ] - : [] - } - onSearchChange={(searchValue: string) => { - setAggregationOptions( - CUSTOM_METRIC_AGGREGATION_OPTIONS.filter(({ value }) => - value.includes(searchValue) - ) - ); - }} - options={aggregationOptions} - /> - )} - /> - - - {watch(`indicator.params.${type}.metrics.${index}.aggregation`) !== 'doc_count' && ( + + + - {metricLabel} {metric.name} {metricTooltip} + {i18n.translate('xpack.slo.sloEdit.customMetric.aggregationLabel', { + defaultMessage: 'Aggregation', + })}{' '} + {metric.name} } > ( metricField.name === field.value) + CUSTOM_METRIC_AGGREGATION_OPTIONS.some( + (agg) => agg.value === field.value + ) ? [ { value: field.value, - label: field.value, + label: aggValueToLabel(field.value), }, ] : [] } onSearchChange={(searchValue: string) => { - setOptions( - createOptionsFromFields(metricFields, ({ value }) => + setAggregationOptions( + CUSTOM_METRIC_AGGREGATION_OPTIONS.filter(({ value }) => value.includes(searchValue) ) ); }} - options={options} + options={aggregationOptions} /> )} /> - )} - - - + {watch(`indicator.params.${type}.metrics.${index}.aggregation`) !== 'doc_count' && ( + + + {metricLabel} {metric.name} {metricTooltip} + + } + > + ( + { + if (selected.length) { + return field.onChange(selected[0].value); + } + field.onChange(''); + }} + selectedOptions={ + !!indexPattern && + !!field.value && + metricFields.some((metricField) => metricField.name === field.value) + ? [ + { + value: field.value, + label: field.value, + }, + ] + : [] + } + onSearchChange={(searchValue: string) => { + setOptions( + createOptionsFromFields(metricFields, ({ value }) => + value.includes(searchValue) + ) + ); + }} + options={options} + /> + )} + /> + + + )} + + + + + + } + /> - - } - /> {index !== arr.length - 1 && }
          ))} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx similarity index 98% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx index 009504e5e6979..3b435fa52494b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx @@ -19,9 +19,9 @@ import { DataView, FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import React, { Fragment, useEffect, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; -import { QueryBuilder } from '../common/query_builder'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { QueryBuilder } from '../../common/query_builder'; interface HistogramIndicatorProps { type: 'good' | 'total'; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx index 6bb1918dba3c2..2e934c74d9d0e 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx @@ -18,11 +18,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { GroupByField } from '../common/group_by_field'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { GroupByField } from '../../common/group_by_field'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { HistogramIndicator } from './histogram_indicator'; @@ -49,7 +49,7 @@ export function HistogramIndicatorTypeForm() { - + diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx similarity index 100% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx similarity index 93% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx index 07f2f86663292..88dbb16d667b6 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx @@ -17,12 +17,12 @@ import moment from 'moment'; import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { formatAllFilters } from '../../helpers/format_filters'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { GroupByCardinality } from '../common/group_by_cardinality'; -import { QueryBuilder } from '../common/query_builder'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { formatAllFilters } from '../../../helpers/format_filters'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { GroupByCardinality } from '../../common/group_by_cardinality'; +import { QueryBuilder } from '../../common/query_builder'; import { FieldSelector } from '../synthetics_common/field_selector'; export function SyntheticsAvailabilityIndicatorTypeForm() { @@ -74,8 +74,8 @@ export function SyntheticsAvailabilityIndicatorTypeForm() { }, [currentMonitors, setValue]); return ( - - + + - + {fields?.map((metric, index, arr) => ( - - - - - + + + - + + + + + + } + /> - - } - /> {index !== arr.length - 1 && } ))} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx similarity index 97% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx index ebb539b97dab2..ef798305b20d6 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx @@ -16,9 +16,9 @@ import { FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { AGGREGATION_OPTIONS, aggValueToLabel } from '../../helpers/aggregation_options'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; +import { AGGREGATION_OPTIONS, aggValueToLabel } from '../../../helpers/aggregation_options'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; const fieldLabel = i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.fieldLabel', { defaultMessage: 'Field', diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx similarity index 88% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx index 86eede0ba65e2..73bc3135d91ac 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx @@ -19,15 +19,15 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { useKibana } from '../../../../hooks/use_kibana'; -import { GroupByField } from '../common/group_by_field'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { useKibana } from '../../../../../hooks/use_kibana'; +import { GroupByField } from '../../common/group_by_field'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { MetricIndicator } from './metric_indicator'; -import { COMPARATOR_MAPPING } from '../../constants'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; +import { COMPARATOR_MAPPING } from '../../../constants'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; export { NEW_TIMESLICE_METRIC } from './metric_indicator'; @@ -54,7 +54,7 @@ export function TimesliceMetricIndicatorTypeForm() { - + diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx index 7ffc274ffce12..9082d5367670e 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx @@ -5,43 +5,56 @@ * 2.0. */ -import { EuiFlexGroup, EuiSpacer, EuiSteps } from '@elastic/eui'; +import { EuiFlexGroup, EuiSteps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { GetSLOResponse } from '@kbn/slo-schema'; +import type { CreateSLOInput, GetSLOResponse } from '@kbn/slo-schema'; +import { RecursivePartial } from '@kbn/utility-types'; import React from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { RecursivePartial } from '@kbn/utility-types'; -import { SloEditFormFooter } from './slo_edit_form_footer'; import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../constants'; -import { transformSloResponseToCreateSloForm } from '../helpers/process_slo_form_values'; +import { + transformPartialSLOStateToFormState, + transformSloResponseToCreateSloForm, +} from '../helpers/process_slo_form_values'; import { useParseUrlState } from '../hooks/use_parse_url_state'; import { useSectionFormValidation } from '../hooks/use_section_form_validation'; import { useShowSections } from '../hooks/use_show_sections'; import { CreateSLOForm } from '../types'; import { SloEditFormDescriptionSection } from './slo_edit_form_description_section'; +import { SloEditFormFooter } from './slo_edit_form_footer'; import { SloEditFormIndicatorSection } from './slo_edit_form_indicator_section'; import { SloEditFormObjectiveSection } from './slo_edit_form_objective_section'; export interface Props { slo?: GetSLOResponse; - initialValues?: RecursivePartial; + initialValues?: RecursivePartial; onSave?: () => void; } -export const maxWidth = 900; - export function SloEditForm({ slo, initialValues, onSave }: Props) { const isEditMode = slo !== undefined; + const isFlyoutMode = initialValues !== undefined && onSave !== undefined; - const sloFormValuesFromUrlState = useParseUrlState() ?? (initialValues as CreateSLOForm); + const sloFormValuesFromFlyoutState = isFlyoutMode + ? transformPartialSLOStateToFormState(initialValues) + : undefined; + const sloFormValuesFromUrlState = useParseUrlState(); const sloFormValuesFromSloResponse = transformSloResponseToCreateSloForm(slo); - const methods = useForm({ - defaultValues: sloFormValuesFromUrlState ?? SLO_EDIT_FORM_DEFAULT_VALUES, - values: sloFormValuesFromUrlState ? sloFormValuesFromUrlState : sloFormValuesFromSloResponse, + const form = useForm({ + defaultValues: isFlyoutMode + ? sloFormValuesFromFlyoutState + : sloFormValuesFromUrlState + ? sloFormValuesFromUrlState + : sloFormValuesFromSloResponse ?? SLO_EDIT_FORM_DEFAULT_VALUES, + values: isFlyoutMode + ? sloFormValuesFromFlyoutState + : sloFormValuesFromUrlState + ? sloFormValuesFromUrlState + : sloFormValuesFromSloResponse, mode: 'all', }); - const { watch, getFieldState, getValues, formState } = methods; + const { watch, getFieldState, getValues, formState } = form; const { isIndicatorSectionValid, isObjectiveSectionValid, isDescriptionSectionValid } = useSectionFormValidation({ @@ -59,41 +72,37 @@ export function SloEditForm({ slo, initialValues, onSave }: Props) { ); return ( - <> - - - , - status: isIndicatorSectionValid ? 'complete' : 'incomplete', - }, - { - title: i18n.translate('xpack.slo.sloEdit.objectives.title', { - defaultMessage: 'Set objectives', - }), - children: showObjectiveSection ? : null, - status: showObjectiveSection && isObjectiveSectionValid ? 'complete' : 'incomplete', - }, - { - title: i18n.translate('xpack.slo.sloEdit.description.title', { - defaultMessage: 'Describe SLO', - }), - children: showDescriptionSection ? : null, - status: - showDescriptionSection && isDescriptionSectionValid ? 'complete' : 'incomplete', - }, - ]} - /> - - + + + , + status: isIndicatorSectionValid ? 'complete' : 'incomplete', + }, + { + title: i18n.translate('xpack.slo.sloEdit.objectives.title', { + defaultMessage: 'Set objectives', + }), + children: showObjectiveSection ? : null, + status: showObjectiveSection && isObjectiveSectionValid ? 'complete' : 'incomplete', + }, + { + title: i18n.translate('xpack.slo.sloEdit.description.title', { + defaultMessage: 'Describe SLO', + }), + children: showDescriptionSection ? : null, + status: + showDescriptionSection && isDescriptionSectionValid ? 'complete' : 'incomplete', + }, + ]} + /> - - - - + + + ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx index a210021674f6b..f242669e566d2 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx @@ -9,8 +9,6 @@ import { EuiComboBox, EuiComboBoxOptionOption, EuiFieldText, - EuiFlexGroup, - EuiFlexItem, EuiFormRow, EuiPanel, EuiTextArea, @@ -20,9 +18,9 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useFetchSLOSuggestions } from '../hooks/use_fetch_suggestions'; -import { OptionalText } from './common/optional_text'; import { CreateSLOForm } from '../types'; -import { maxWidth } from './slo_edit_form'; +import { OptionalText } from './common/optional_text'; +import { MAX_WIDTH } from '../constants'; export function SloEditFormDescriptionSection() { const { control, getFieldState } = useFormContext(); @@ -37,129 +35,117 @@ export function SloEditFormDescriptionSection() { hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormDescriptionSection" > - - - - ( - - )} + + ( + - - + )} + /> +
          - - } - > - ( - + } + > + ( + - - + )} + /> +
          - - - ( - { - if (selected.length) { - return field.onChange(selected.map((opts) => opts.value)); - } + + ( + { + if (selected.length) { + return field.onChange(selected.map((opts) => opts.value)); + } - field.onChange([]); - }} - onCreateOption={( - searchValue: string, - options: EuiComboBoxOptionOption[] = [] - ) => { - const normalizedSearchValue = searchValue.trim().toLowerCase(); + field.onChange([]); + }} + onCreateOption={(searchValue: string, options: EuiComboBoxOptionOption[] = []) => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); - if (!normalizedSearchValue) { - return; - } - const values = field.value ?? []; + if (!normalizedSearchValue) { + return; + } + const values = field.value ?? []; - if ( - values.findIndex( - (tag) => tag.trim().toLowerCase() === normalizedSearchValue - ) === -1 - ) { - field.onChange([...values, searchValue]); - } - }} - isClearable - data-test-subj="sloEditTagsSelector" - /> - )} + if ( + values.findIndex((tag) => tag.trim().toLowerCase() === normalizedSearchValue) === + -1 + ) { + field.onChange([...values, searchValue]); + } + }} + isClearable + data-test-subj="sloEditTagsSelector" /> - - -
          + )} + /> + ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx index 156f45c2c982c..4d30bef7ac692 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx @@ -7,19 +7,20 @@ import { EuiFormRow, EuiPanel, EuiSelect, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { assertNever } from '@kbn/std'; import React, { useMemo } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { SLI_OPTIONS } from '../constants'; import { useUnregisterFields } from '../hooks/use_unregister_fields'; import { CreateSLOForm } from '../types'; -import { ApmAvailabilityIndicatorTypeForm } from './apm_availability/apm_availability_indicator_type_form'; -import { ApmLatencyIndicatorTypeForm } from './apm_latency/apm_latency_indicator_type_form'; -import { SyntheticsAvailabilityIndicatorTypeForm } from './synthetics_availability/synthetics_availability_indicator_type_form'; -import { CustomKqlIndicatorTypeForm } from './custom_kql/custom_kql_indicator_type_form'; -import { CustomMetricIndicatorTypeForm } from './custom_metric/custom_metric_type_form'; -import { HistogramIndicatorTypeForm } from './histogram/histogram_indicator_type_form'; -import { maxWidth } from './slo_edit_form'; -import { TimesliceMetricIndicatorTypeForm } from './timeslice_metric/timeslice_metric_indicator'; +import { MAX_WIDTH } from '../constants'; +import { ApmAvailabilityIndicatorTypeForm } from './indicator_section/apm_availability/apm_availability_indicator_type_form'; +import { ApmLatencyIndicatorTypeForm } from './indicator_section/apm_latency/apm_latency_indicator_type_form'; +import { CustomKqlIndicatorTypeForm } from './indicator_section/custom_kql/custom_kql_indicator_type_form'; +import { CustomMetricIndicatorTypeForm } from './indicator_section/custom_metric/custom_metric_type_form'; +import { HistogramIndicatorTypeForm } from './indicator_section/histogram/histogram_indicator_type_form'; +import { SyntheticsAvailabilityIndicatorTypeForm } from './indicator_section/synthetics_availability/synthetics_availability_indicator_type_form'; +import { TimesliceMetricIndicatorTypeForm } from './indicator_section/timeslice_metric/timeslice_metric_indicator'; interface SloEditFormIndicatorSectionProps { isEditMode: boolean; @@ -48,7 +49,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator case 'sli.metric.timeslice': return ; default: - return null; + assertNever(indicatorType); } }, [indicatorType]); @@ -57,7 +58,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormIndicatorSection" > {!isEditMode && ( @@ -78,7 +79,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator )} /> - + )} {indicatorTypeForm} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx index 15c51b1b86ce4..65e4a25a86c39 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx @@ -7,15 +7,14 @@ import { EuiCallOut, - EuiCheckbox, EuiFieldNumber, EuiFlexGrid, + EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip, EuiPanel, EuiSelect, - EuiSpacer, useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -30,7 +29,8 @@ import { TIMEWINDOW_TYPE_OPTIONS, } from '../constants'; import { CreateSLOForm } from '../types'; -import { maxWidth } from './slo_edit_form'; +import { MAX_WIDTH } from '../constants'; +import { AdvancedSettings } from './indicator_section/advanced_settings/advanced_settings'; import { SloEditFormObjectiveSectionTimeslices } from './slo_edit_form_objective_section_timeslices'; export function SloEditFormObjectiveSection() { @@ -44,7 +44,6 @@ export function SloEditFormObjectiveSection() { const budgetingSelect = useGeneratedHtmlId({ prefix: 'budgetingSelect' }); const timeWindowTypeSelect = useGeneratedHtmlId({ prefix: 'timeWindowTypeSelect' }); const timeWindowSelect = useGeneratedHtmlId({ prefix: 'timeWindowSelect' }); - const preventBackfillCheckbox = useGeneratedHtmlId({ prefix: 'preventBackfill' }); const timeWindowType = watch('timeWindow.type'); const indicator = watch('indicator.type'); @@ -91,237 +90,199 @@ export function SloEditFormObjectiveSection() { hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormObjectiveSection" > - - - - {i18n.translate('xpack.slo.sloEdit.timeWindowType.label', { - defaultMessage: 'Time window', - })}{' '} - - - } - > - ( - - )} - /> - - - - - {i18n.translate('xpack.slo.sloEdit.timeWindowDuration.label', { - defaultMessage: 'Duration', - })}{' '} - - - } - > - ( - - )} - /> - - - - - - {indicator === 'sli.metric.timeslice' && ( - - -

          - + + + + {i18n.translate('xpack.slo.sloEdit.timeWindowType.label', { + defaultMessage: 'Time window', + })}{' '} + + + } + > + ( + + )} /> -

          -
          - -
          - )} - - {indicator === 'sli.synthetics.availability' && ( - - -

          - + + + + {i18n.translate('xpack.slo.sloEdit.timeWindowDuration.label', { + defaultMessage: 'Duration', + })}{' '} + + + } + > + ( + + )} /> -

          -
          - -
          - )} + +
          + - - - - {i18n.translate('xpack.slo.sloEdit.budgetingMethod.label', { - defaultMessage: 'Budgeting method', - })}{' '} - - - } - > - ( - + +

          + - )} - /> - - +

          +
          +
          + )} - {watch('budgetingMethod') === 'timeslices' ? ( - - ) : null} -
          + {indicator === 'sli.synthetics.availability' && ( + + +

          + +

          +
          +
          + )} - + + + + {i18n.translate('xpack.slo.sloEdit.budgetingMethod.label', { + defaultMessage: 'Budgeting method', + })}{' '} + + + } + > + ( + + )} + /> + + - - - - {i18n.translate('xpack.slo.sloEdit.targetSlo.label', { - defaultMessage: 'Target / SLO (%)', - })}{' '} - - - } - > - ( - onChange(event.target.value)} - /> - )} - /> - - - + {watch('budgetingMethod') === 'timeslices' ? ( + + ) : null} + - + + + + {i18n.translate('xpack.slo.sloEdit.targetSlo.label', { + defaultMessage: 'Target / SLO (%)', + })}{' '} + + + } + > + ( + onChange(event.target.value)} + /> + )} + /> + + + - - - - ( - - {i18n.translate('xpack.slo.sloEdit.settings.preventInitialBackfill.label', { - defaultMessage: 'Prevent initial backfill of data', - })} - - - } - checked={Boolean(field.value)} - onChange={(event: any) => onChange(event.target.checked)} - /> - )} - /> - - - + +
          ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts index 123ebdc660947..55dfec93f8a33 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts @@ -33,6 +33,8 @@ import { import { SYNTHETICS_DEFAULT_GROUPINGS, SYNTHETICS_INDEX_PATTERN } from '../../../common/constants'; import { CreateSLOForm } from './types'; +export const MAX_WIDTH = 900; + export const SLI_OPTIONS: Array<{ value: IndicatorType; text: string; @@ -205,6 +207,13 @@ export const SYNTHETICS_AVAILABILITY_DEFAULT_VALUES: SyntheticsAvailabilityIndic }, }; +export const SETTINGS_DEFAULT_VALUES = { + frequency: 1, + preventInitialBackfill: false, + syncDelay: 1, + syncField: null, +}; + export const SLO_EDIT_FORM_DEFAULT_VALUES: CreateSLOForm = { name: '', description: '', @@ -219,9 +228,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES: CreateSLOForm = { target: 99, }, groupBy: ALL_VALUE, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC: CreateSLOForm = { @@ -238,9 +245,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC: CreateSLOForm = { target: 99, }, groupBy: ALL_VALUE, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY: CreateSLOForm = { @@ -257,9 +262,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY: CreateSLOForm target: 99, }, groupBy: SYNTHETICS_DEFAULT_GROUPINGS, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const COMPARATOR_GT = i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.gtLabel', { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap index 3f7ac0ce83beb..78f63a4b8f7bc 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap @@ -26,7 +26,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -74,7 +77,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -104,7 +110,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -146,7 +155,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -178,7 +190,10 @@ Object { "timesliceWindow": "2", }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -208,7 +223,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -218,6 +236,105 @@ Object { } `; +exports[`Transform partial URL state into form state settings handles optional 'syncField' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": "override-field", + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + +exports[`Transform partial URL state into form state settings handles partial 'settings' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": false, + "syncDelay": 12, + "syncField": null, + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + +exports[`Transform partial URL state into form state settings handles the 'settings' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": true, + "syncDelay": 180, + "syncField": null, + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + exports[`Transform partial URL state into form state with 'indicator' in URL state handles partial APM Availability state 1`] = ` Object { "budgetingMethod": "occurrences", @@ -239,7 +356,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -271,7 +391,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -301,7 +424,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -331,7 +457,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts index 16ad733619e65..c79571d4ab77b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { getGroupByCardinalityFilters } from '../components/synthetics_availability/synthetics_availability_indicator_type_form'; +import { getGroupByCardinalityFilters } from '../components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form'; import { formatAllFilters } from './format_filters'; describe('formatAllFilters', () => { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts index a69cd1152985c..7518e1c679c87 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { transformPartialUrlStateToFormState as transform } from './process_slo_form_values'; +import { transformPartialSLOStateToFormState as transform } from './process_slo_form_values'; describe('Transform partial URL state into form state', () => { describe("with 'indicator' in URL state", () => { @@ -121,4 +121,20 @@ describe('Transform partial URL state into form state', () => { }) ).toMatchSnapshot(); }); + + describe('settings', () => { + it("handles the 'settings' URL state", () => { + expect( + transform({ settings: { preventInitialBackfill: true, syncDelay: '3h' } }) + ).toMatchSnapshot(); + }); + + it("handles partial 'settings' URL state", () => { + expect(transform({ settings: { syncDelay: '12m' } })).toMatchSnapshot(); + }); + + it("handles optional 'syncField' URL state", () => { + expect(transform({ settings: { syncField: 'override-field' } })).toMatchSnapshot(); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts index 8bbbcf9d2fee9..81d6714dac2e5 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts @@ -9,13 +9,14 @@ import { CreateSLOInput, GetSLOResponse, Indicator, UpdateSLOInput } from '@kbn/ import { assertNever } from '@kbn/std'; import { RecursivePartial } from '@kbn/utility-types'; import { cloneDeep } from 'lodash'; -import { toDuration } from '../../../utils/slo/duration'; +import { toDuration, toMinutes } from '../../../utils/slo/duration'; import { APM_AVAILABILITY_DEFAULT_VALUES, APM_LATENCY_DEFAULT_VALUES, CUSTOM_KQL_DEFAULT_VALUES, CUSTOM_METRIC_DEFAULT_VALUES, HISTOGRAM_DEFAULT_VALUES, + SETTINGS_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY, SYNTHETICS_AVAILABILITY_DEFAULT_VALUES, @@ -52,6 +53,13 @@ export function transformSloResponseToCreateSloForm( tags: values.tags, settings: { preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + syncDelay: values.settings?.syncDelay + ? toMinutes(toDuration(values.settings.syncDelay)) + : SETTINGS_DEFAULT_VALUES.syncDelay, + frequency: values.settings?.frequency + ? toMinutes(toDuration(values.settings.frequency)) + : SETTINGS_DEFAULT_VALUES.frequency, + syncField: values.settings?.syncField ?? null, }, }; } @@ -80,7 +88,10 @@ export function transformCreateSLOFormToCreateSLOInput(values: CreateSLOForm): C tags: values.tags, groupBy: [values.groupBy].flat(), settings: { - preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + preventInitialBackfill: values.settings.preventInitialBackfill, + syncDelay: `${values.settings.syncDelay ?? SETTINGS_DEFAULT_VALUES.syncDelay}m`, + frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`, + syncField: values.settings.syncField, }, }; } @@ -109,7 +120,10 @@ export function transformValuesToUpdateSLOInput(values: CreateSLOForm): UpdateSL tags: values.tags, groupBy: [values.groupBy].flat(), settings: { - preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + preventInitialBackfill: values.settings.preventInitialBackfill, + syncDelay: `${values.settings.syncDelay ?? SETTINGS_DEFAULT_VALUES.syncDelay}m`, + frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`, + syncField: values.settings.syncField, }, }; } @@ -165,7 +179,7 @@ function transformPartialIndicatorState( } } -export function transformPartialUrlStateToFormState( +export function transformPartialSLOStateToFormState( values: RecursivePartial ): CreateSLOForm { let state: CreateSLOForm; @@ -189,8 +203,8 @@ export function transformPartialUrlStateToFormState( if (values.description) { state.description = values.description; } - if (!!values.tags) { - state.tags = values.tags as string[]; + if (values.tags) { + state.tags = [values.tags].flat().filter((tag) => !!tag) as string[]; } if (values.objective) { @@ -220,8 +234,19 @@ export function transformPartialUrlStateToFormState( state.timeWindow = { duration: values.timeWindow.duration, type: values.timeWindow.type }; } - if (!!values.settings?.preventInitialBackfill) { - state.settings = { preventInitialBackfill: values.settings.preventInitialBackfill }; + if (!!values.settings) { + if (values.settings.preventInitialBackfill) { + state.settings.preventInitialBackfill = values.settings.preventInitialBackfill; + } + if (values.settings.syncDelay) { + state.settings.syncDelay = toMinutes(toDuration(values.settings.syncDelay)); + } + if (values.settings.frequency) { + state.settings.frequency = toMinutes(toDuration(values.settings.frequency)); + } + if (values.settings.syncField) { + state.settings.syncField = values.settings.syncField; + } } return state; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts index 2c305feda3c06..9ada81ea84387 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts @@ -10,7 +10,7 @@ import { CreateSLOInput } from '@kbn/slo-schema'; import { RecursivePartial } from '@kbn/utility-types'; import { useHistory } from 'react-router-dom'; import { useMemo } from 'react'; -import { transformPartialUrlStateToFormState } from '../helpers/process_slo_form_values'; +import { transformPartialSLOStateToFormState } from '../helpers/process_slo_form_values'; import { CreateSLOForm } from '../types'; export function useParseUrlState(): CreateSLOForm | undefined { @@ -25,6 +25,6 @@ export function useParseUrlState(): CreateSLOForm | undefined { const urlState = urlStateStorage.get>('_a'); - return !!urlState ? transformPartialUrlStateToFormState(urlState) : undefined; + return !!urlState ? transformPartialSLOStateToFormState(urlState) : undefined; }, [history]); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts index 7d75359f4cd40..94ffc92adedb4 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts @@ -220,8 +220,10 @@ export function useSectionFormValidation({ getFieldState, getValues, formState, 'objective.target', 'objective.timesliceTarget', 'objective.timesliceWindow', + 'settings.syncDelay', + 'settings.frequency', ] as const - ).every((field) => getFieldState(field).error === undefined); + ).every((field) => !getFieldState(field).invalid); const isDescriptionSectionValid = !getFieldState('name').invalid && diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts index 9d7752f190344..eb7a77f822660 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts @@ -19,8 +19,8 @@ import { CUSTOM_METRIC_DEFAULT_VALUES, HISTOGRAM_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES, - TIMESLICE_METRIC_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY, + TIMESLICE_METRIC_DEFAULT_VALUES, } from '../constants'; import { CreateSLOForm } from '../types'; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx index 98c76b190aa1a..f71d7caa80d17 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx @@ -7,12 +7,11 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { CreateSLOInput } from '@kbn/slo-schema'; import { RecursivePartial } from '@kbn/utility-types'; -import { merge } from 'lodash'; import React from 'react'; import { OutPortal, createHtmlPortalNode } from 'react-reverse-portal'; import { SloEditForm } from '../components/slo_edit_form'; -import { CreateSLOForm } from '../types'; export const sloEditFormFooterPortal = createHtmlPortalNode(); @@ -22,7 +21,7 @@ export default function SloAddFormFlyout({ initialValues, }: { onClose: () => void; - initialValues?: RecursivePartial; + initialValues?: RecursivePartial; }) { return ( - + diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx index abc60d6a00352..8d52ed914302c 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx @@ -423,11 +423,11 @@ describe('SLO Edit Page', () => { jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123' }); history.push( - '/slos/123/edit?_a=(name:%27updated-name%27,indicator:(params:(environment:prod,service:cartService),type:sli.apm.transactionDuration),objective:(target:0.92))' + '/slos/edit/123?_a=(name:%27updated-name%27,indicator:(params:(environment:prod,service:cartService),type:sli.apm.transactionDuration),objective:(target:0.92))' ); jest .spyOn(Router, 'useLocation') - .mockReturnValue({ pathname: '/slos/123/edit', search: '', state: '', hash: '' }); + .mockReturnValue({ pathname: '/slos/edit/123', search: '', state: '', hash: '' }); useFetchSloMock.mockReturnValue({ isLoading: false, data: slo }); @@ -463,8 +463,7 @@ describe('SLO Edit Page', () => { jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123' }); jest .spyOn(Router, 'useLocation') - .mockReturnValue({ pathname: '/slos/123/edit', search: '', state: '', hash: '' }); - + .mockReturnValue({ pathname: '/slos/edit/123', search: '', state: '', hash: '' }); useFetchSloMock.mockReturnValue({ isLoading: false, data: slo }); const { getByTestId } = render(); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx index b014bdb1d6dec..0a563bbe75b44 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx @@ -12,10 +12,10 @@ import { useParams } from 'react-router-dom'; import { paths } from '../../../common/locators/paths'; import { HeaderMenu } from '../../components/header_menu/header_menu'; import { useFetchSloDetails } from '../../hooks/use_fetch_slo_details'; +import { useKibana } from '../../hooks/use_kibana'; import { useLicense } from '../../hooks/use_license'; import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { useKibana } from '../../hooks/use_kibana'; import { SloEditForm } from './components/slo_edit_form'; export function SloEditPage() { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts index 5eef9a2d0e5ba..6584e52404bc5 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts @@ -25,5 +25,8 @@ export interface CreateSLOForm { groupBy: string[] | string; settings: { preventInitialBackfill: boolean; + syncDelay: number; // in minutes + frequency: number; // in minutes + syncField: string | null; }; } diff --git a/x-pack/plugins/observability_solution/slo/public/types.ts b/x-pack/plugins/observability_solution/slo/public/types.ts index 964fb9b289ea3..80439c4a4134c 100644 --- a/x-pack/plugins/observability_solution/slo/public/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/types.ts @@ -15,6 +15,7 @@ import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/pub import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { DiscoverStart } from '@kbn/discover-plugin/public'; import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; +import type { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; @@ -82,6 +83,7 @@ export interface SLOPublicPluginsStart { discover?: DiscoverStart; discoverShared: DiscoverSharedPublicStart; embeddable: EmbeddableStart; + embeddableEnhanced?: EmbeddableEnhancedPluginStart; fieldFormats: FieldFormatsStart; lens: LensPublicStart; licensing: LicensingPluginStart; diff --git a/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts b/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts index 3c0495fd1bc9b..6f44d13150819 100644 --- a/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts @@ -51,7 +51,7 @@ describe('remote SLO URLs Utils', () => { `"https://cloud.elast.co/app/slos/edit/fixed-id"` ); expect(createRemoteSloCloneUrl(remoteSlo)).toMatchInlineSnapshot( - `"https://cloud.elast.co/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` + `"https://cloud.elast.co/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` ); }); @@ -71,7 +71,7 @@ describe('remote SLO URLs Utils', () => { `"https://cloud.elast.co/s/my-custom-space/app/slos/edit/fixed-id"` ); expect(createRemoteSloCloneUrl(remoteSlo, 'my-custom-space')).toMatchInlineSnapshot( - `"https://cloud.elast.co/s/my-custom-space/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` + `"https://cloud.elast.co/s/my-custom-space/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` ); }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts index d432dc5c52d34..ace1a1318ce29 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IBasePath, Logger } from '@kbn/core/server'; import { IRuleDataService } from '@kbn/rule-registry-plugin/server'; import { CustomThresholdLocators } from '@kbn/observability-plugin/server'; import { sloBurnRateRuleType } from './slo_burn_rate'; export function registerBurnRateRule( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, basePath: IBasePath, logger: Logger, ruleDataService: IRuleDataService, diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts index 6b6c85f9120f6..e5c07b797677b 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts @@ -204,6 +204,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }) ).rejects.toThrowError(); }); @@ -226,6 +227,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(esClientMock.search).not.toHaveBeenCalled(); @@ -276,6 +278,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).not.toBeCalled(); @@ -323,6 +326,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).not.toBeCalled(); @@ -382,6 +386,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -531,6 +536,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -651,6 +657,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient!.report).toBeCalledWith({ diff --git a/x-pack/plugins/observability_solution/slo/server/plugin.ts b/x-pack/plugins/observability_solution/slo/server/plugin.ts index 7699cbe5f1404..99cd4a2230a94 100644 --- a/x-pack/plugins/observability_solution/slo/server/plugin.ts +++ b/x-pack/plugins/observability_solution/slo/server/plugin.ts @@ -14,10 +14,11 @@ import { PluginInitializerContext, SavedObjectsClient, } from '@kbn/core/server'; -import { KibanaFeatureScope } from '@kbn/features-plugin/common'; -import { i18n } from '@kbn/i18n'; import { AlertsLocatorDefinition, sloFeatureId } from '@kbn/observability-plugin/common'; import { SLO_BURN_RATE_RULE_TYPE_ID } from '@kbn/rule-data-utils'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; +import { KibanaFeatureScope } from '@kbn/features-plugin/common'; +import { i18n } from '@kbn/i18n'; import { mapValues } from 'lodash'; import { registerSloUsageCollector } from './lib/collectors/register'; import { registerBurnRateRule } from './lib/rules/register_burn_rate_rule'; @@ -61,6 +62,11 @@ export class SLOPlugin const savedObjectTypes = [SO_SLO_TYPE, SO_SLO_SETTINGS_TYPE]; + const alertingFeatures = sloRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [sloFeatureId, ALERTING_FEATURE_ID], + })); + plugins.features.registerKibanaFeature({ id: sloFeatureId, name: i18n.translate('xpack.slo.featureRegistry.linkSloTitle', { @@ -71,7 +77,7 @@ export class SLOPlugin scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], app: [sloFeatureId, 'kibana'], catalogue: [sloFeatureId, 'observability'], - alerting: sloRuleTypes, + alerting: alertingFeatures, privileges: { all: { app: [sloFeatureId, 'kibana'], @@ -83,10 +89,10 @@ export class SLOPlugin }, alerting: { rule: { - all: sloRuleTypes, + all: alertingFeatures, }, alert: { - all: sloRuleTypes, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -101,10 +107,10 @@ export class SLOPlugin }, alerting: { rule: { - read: sloRuleTypes, + read: alertingFeatures, }, alert: { - read: sloRuleTypes, + read: alertingFeatures, }, }, ui: ['read'], diff --git a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts index e7c09c352bd66..a8e01fb4681f4 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts @@ -9,6 +9,7 @@ import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typ import { ElasticsearchClient, IBasePath, IScopedClusterClient, Logger } from '@kbn/core/server'; import { ALL_VALUE, CreateSLOParams, CreateSLOResponse } from '@kbn/slo-schema'; import { asyncForEach } from '@kbn/std'; +import { merge } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { SLO_MODEL_VERSION, @@ -46,8 +47,10 @@ export class CreateSLO { const slo = this.toSLO(params); validateSLO(slo); - await this.assertSLOInexistant(slo); - await assertExpectedIndicatorSourceIndexPrivileges(slo, this.esClient); + await Promise.all([ + this.assertSLOInexistant(slo), + assertExpectedIndicatorSourceIndexPrivileges(slo, this.esClient), + ]); const rollbackOperations = []; const createPromise = this.repository.create(slo); @@ -201,11 +204,14 @@ export class CreateSLO { return { ...params, id: params.id ?? uuidv4(), - settings: { - syncDelay: params.settings?.syncDelay ?? new Duration(1, DurationUnit.Minute), - frequency: params.settings?.frequency ?? new Duration(1, DurationUnit.Minute), - preventInitialBackfill: params.settings?.preventInitialBackfill ?? false, - }, + settings: merge( + { + syncDelay: new Duration(1, DurationUnit.Minute), + frequency: new Duration(1, DurationUnit.Minute), + preventInitialBackfill: false, + }, + params.settings + ), revision: params.revision ?? 1, enabled: true, tags: params.tags ?? [], diff --git a/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts b/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts index 32660b68f4693..fb2be7bcbf74d 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts @@ -15,7 +15,7 @@ import { import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; import { AlertsClient } from '@kbn/rule-registry-plugin/server'; import moment from 'moment'; -import { observabilityAlertFeatureIds } from '@kbn/observability-plugin/common'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { typedSearch } from '../utils/queries'; import { getElasticsearchQueryOrThrow, parseStringFilters } from './transform_generators'; import { getListOfSummaryIndices, getSloSettings } from './slo_settings'; @@ -108,21 +108,16 @@ export class GetSLOsOverview { const [rules, alerts] = await Promise.all([ this.rulesClient.find({ options: { - search: 'alert.attributes.alertTypeId:("slo.rules.burnRate")', + ruleTypeIds: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], }, }), this.racClient.getAlertSummary({ - featureIds: observabilityAlertFeatureIds, + ruleTypeIds: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], gte: moment().subtract(24, 'hours').toISOString(), lte: moment().toISOString(), - filter: [ - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, - ], }), ]); diff --git a/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts b/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts index 4f9cf439e8ed1..afbdb999fc064 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts @@ -9,6 +9,7 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { Logger } from '@kbn/core/server'; import { ALL_VALUE, Paginated, Pagination, sloDefinitionSchema } from '@kbn/slo-schema'; import { isLeft } from 'fp-ts/lib/Either'; +import { merge } from 'lodash'; import { SLO_MODEL_VERSION } from '../../common/constants'; import { SLODefinition, StoredSLODefinition } from '../domain/models'; import { SLONotFound } from '../errors'; @@ -155,10 +156,10 @@ export class KibanaSavedObjectsSLORepository implements SLORepository { // We would need to call the _reset api on this SLO. version: storedSLO.version ?? 1, // settings.preventInitialBackfill was added in 8.15.0 - settings: { - ...storedSLO.settings, - preventInitialBackfill: storedSLO.settings?.preventInitialBackfill ?? false, - }, + settings: merge( + { preventInitialBackfill: false, syncDelay: '1m', frequency: '1m' }, + storedSLO.settings + ), }); if (isLeft(result)) { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap index 7d8e989c1140d..f49785cf936c5 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap @@ -63,3 +63,11 @@ Object { }, } `; + +exports[`Transform Generator settings builds the transform settings 1`] = ` +Object { + "frequency": "2m", + "sync_delay": "10m", + "sync_field": "my_timestamp_sync_field", +} +`; diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts index d1f05605dab36..99361fa776789 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts @@ -42,7 +42,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo, slo.indicator), - this.buildSettings(slo), + this.buildSettings(slo, '@timestamp'), slo ); } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts index 6adbd1d3eae9f..a65e4ae1d50dd 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts @@ -41,7 +41,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo), - this.buildSettings(slo), + this.buildSettings(slo, '@timestamp'), slo ); } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts index e70d406d75396..2df8a1e40eebb 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { Duration, DurationUnit } from '../../domain/models'; import { createAPMTransactionErrorRateIndicator, createSLO } from '../fixtures/slo'; import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate'; import { dataViewsService } from '@kbn/data-views-plugin/server/mocks'; @@ -45,4 +46,46 @@ describe('Transform Generator', () => { expect(runtimeMappings).toEqual({}); }); }); + + describe('settings', () => { + const defaultSettings = { + syncDelay: new Duration(10, DurationUnit.Minute), + frequency: new Duration(2, DurationUnit.Minute), + preventInitialBackfill: true, + }; + + it('builds the transform settings', async () => { + const slo = createSLO({ + settings: { + ...defaultSettings, + syncField: 'my_timestamp_sync_field', + }, + }); + const settings = generator.buildSettings(slo); + expect(settings).toMatchSnapshot(); + }); + + it('builds the transform settings using the provided settings.syncField', async () => { + const slo = createSLO({ + settings: { + ...defaultSettings, + syncField: 'my_timestamp_sync_field', + }, + }); + const settings = generator.buildSettings(slo, '@timestamp'); + expect(settings.sync_field).toEqual('my_timestamp_sync_field'); + }); + + it('builds the transform settings using provided fallback when no settings.syncField is configured', async () => { + const slo = createSLO({ settings: defaultSettings }); + const settings = generator.buildSettings(slo, '@timestamp2'); + expect(settings.sync_field).toEqual('@timestamp2'); + }); + + it("builds the transform settings using '@timestamp' default fallback when no settings.syncField is configured", async () => { + const slo = createSLO({ settings: defaultSettings }); + const settings = generator.buildSettings(slo); + expect(settings.sync_field).toEqual('@timestamp'); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts index 6c44471fd6566..ea27ebbc7aa38 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts @@ -88,8 +88,9 @@ export abstract class TransformGenerator { ): TransformSettings { return { frequency: slo.settings.frequency.format(), - sync_field: sourceIndexTimestampField, // timestamp field defined in the source index sync_delay: slo.settings.syncDelay.format(), + // 8.17: use settings.syncField if truthy or default to sourceIndexTimestampField which is the indicator timestampField + sync_field: !!slo.settings.syncField ? slo.settings.syncField : sourceIndexTimestampField, }; } } diff --git a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts index d1dfb2e70e00c..402ca82acecd4 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts @@ -43,9 +43,10 @@ export class UpdateSLO { public async execute(sloId: string, params: UpdateSLOParams): Promise { const originalSlo = await this.repository.findById(sloId); - let updatedSlo: SLODefinition = Object.assign({}, originalSlo, params, { + let updatedSlo: SLODefinition = Object.assign({}, originalSlo, { + ...params, groupBy: !!params.groupBy ? params.groupBy : originalSlo.groupBy, - settings: mergePartialSettings(originalSlo.settings, params.settings), + settings: Object.assign({}, originalSlo.settings, params.settings), }); if (isEqual(originalSlo, updatedSlo)) { @@ -263,13 +264,3 @@ export class UpdateSLO { return updateSLOResponseSchema.encode(slo); } } - -/** - * Settings are merged by overwriting the original settings with the optional new partial settings. - */ -function mergePartialSettings( - originalSettings: SLODefinition['settings'], - newPartialSettings: UpdateSLOParams['settings'] -) { - return Object.assign({}, originalSettings, newPartialSettings); -} diff --git a/x-pack/plugins/observability_solution/slo/server/types.ts b/x-pack/plugins/observability_solution/slo/server/types.ts index b9269f49c4d9f..9a40547820182 100644 --- a/x-pack/plugins/observability_solution/slo/server/types.ts +++ b/x-pack/plugins/observability_solution/slo/server/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PluginSetupContract, PluginStartContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; @@ -31,7 +31,7 @@ export interface SLOServerSetup {} export interface SLOServerStart {} export interface SLOPluginSetupDependencies { - alerting: PluginSetupContract; + alerting: AlertingServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; share: SharePluginSetup; features: FeaturesPluginSetup; @@ -44,7 +44,7 @@ export interface SLOPluginSetupDependencies { } export interface SLOPluginStartDependencies { - alerting: PluginStartContract; + alerting: AlertingServerStart; taskManager: TaskManagerStartContract; spaces?: SpacesPluginStart; ruleRegistry: RuleRegistryPluginStartContract; diff --git a/x-pack/plugins/observability_solution/slo/tsconfig.json b/x-pack/plugins/observability_solution/slo/tsconfig.json index 3b01431c3fb45..125a8463be595 100644 --- a/x-pack/plugins/observability_solution/slo/tsconfig.json +++ b/x-pack/plugins/observability_solution/slo/tsconfig.json @@ -30,6 +30,7 @@ "@kbn/alerting-plugin", "@kbn/rison", "@kbn/embeddable-plugin", + "@kbn/embeddable-enhanced-plugin", "@kbn/lens-plugin", "@kbn/ui-theme", "@kbn/es-query", diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts index 4f525bda17564..8a5812f46c6cb 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts @@ -8,6 +8,8 @@ import type { ActionGroup } from '@kbn/alerting-plugin/common'; import { i18n } from '@kbn/i18n'; +export { SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE } from '@kbn/rule-data-utils'; + export type MonitorStatusActionGroup = | ActionGroup<'xpack.synthetics.alerts.actionGroups.monitorStatus'> | ActionGroup<'xpack.synthetics.alerts.actionGroups.tls'>; @@ -34,14 +36,6 @@ export const ACTION_GROUP_DEFINITIONS: { TLS_CERTIFICATE, }; -export const SYNTHETICS_STATUS_RULE = 'xpack.synthetics.alerts.monitorStatus'; -export const SYNTHETICS_TLS_RULE = 'xpack.synthetics.alerts.tls'; - -export const SYNTHETICS_ALERT_RULE_TYPES = { - MONITOR_STATUS: SYNTHETICS_STATUS_RULE, - TLS: SYNTHETICS_TLS_RULE, -}; - -export const SYNTHETICS_RULE_TYPES = [SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE]; - export const SYNTHETICS_RULE_TYPES_ALERT_CONTEXT = 'observability.uptime'; + +export { SYNTHETICS_RULE_TYPE_IDS as SYNTHETICS_RULE_TYPES } from '@kbn/rule-data-utils'; diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts index dd7ad03b9ac32..3bb2c9a4f5aef 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts @@ -291,4 +291,77 @@ describe('Alert Actions factory', () => { }, ]); }); + + it('generate expected action for email opsgenie connector', async () => { + const resp = populateAlertActions({ + groupId: SYNTHETICS_MONITOR_STATUS.id, + defaultActions: [ + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + actionTypeId: '.opsgenie', + group: 'xpack.synthetics.alerts.actionGroups.monitorStatus', + params: {}, + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + }, + ] as unknown as ActionConnector[], + defaultEmail: { + to: ['test@email.com'], + }, + translations: { + defaultActionMessage: SyntheticsMonitorStatusTranslations.defaultActionMessage, + defaultRecoveryMessage: SyntheticsMonitorStatusTranslations.defaultRecoveryMessage, + defaultSubjectMessage: SyntheticsMonitorStatusTranslations.defaultSubjectMessage, + defaultRecoverySubjectMessage: + SyntheticsMonitorStatusTranslations.defaultRecoverySubjectMessage, + }, + }); + expect(resp).toEqual([ + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + group: 'recovered', + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + params: { + subAction: 'closeAlert', + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + description: + 'The alert for monitor "{{context.monitorName}}" from {{context.locationNames}} is no longer active: {{context.recoveryReason}}. - Elastic Synthetics\n\nDetails:\n\n- Monitor name: {{context.monitorName}} \n- {{context.monitorUrlLabel}}: {{{context.monitorUrl}}} \n- Monitor type: {{context.monitorType}} \n- From: {{context.locationNames}} \n- Last error received: {{{context.lastErrorMessage}}} \n{{{context.linkMessage}}}', + message: + 'Monitor "{{context.monitorName}}" ({{context.locationNames}}) {{context.recoveryStatus}} - Elastic Synthetics', + priority: 'P2', + tags: ['{{rule.tags}}'], + }, + }, + }, + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + group: 'xpack.synthetics.alerts.actionGroups.monitorStatus', + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + params: { + subAction: 'createAlert', + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + description: + 'Monitor "{{context.monitorName}}" is {{{context.status}}} from {{context.locationNames}}.{{{context.pendingLastRunAt}}} - Elastic Synthetics\n\nDetails:\n\n- Monitor name: {{context.monitorName}} \n- {{context.monitorUrlLabel}}: {{{context.monitorUrl}}} \n- Monitor type: {{context.monitorType}} \n- Checked at: {{context.checkedAt}} \n- From: {{context.locationNames}} \n- Reason: {{{context.reason}}} \n- Error received: {{{context.lastErrorMessage}}} \n{{{context.linkMessage}}}', + message: + 'Monitor "{{context.monitorName}}" ({{context.locationNames}}) is down - Elastic Synthetics', + priority: 'P2', + tags: ['{{rule.tags}}'], + }, + }, + }, + ]); + }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts index 9b6d9d0992baa..a9981cd257ee6 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts @@ -14,10 +14,12 @@ import type { WebhookActionParams, EmailActionParams, SlackApiActionParams, + OpsgenieActionParams, } from '@kbn/stack-connectors-plugin/server/connector_types'; import { RuleAction as RuleActionOrig } from '@kbn/alerting-plugin/common'; import { v4 as uuidv4 } from 'uuid'; +import { OpsgenieSubActions } from '@kbn/stack-connectors-plugin/common'; import { ActionConnector, ActionTypeId } from './types'; import { DefaultEmail } from '../runtime_types'; @@ -31,6 +33,7 @@ export const SERVICE_NOW_ACTION_ID: ActionTypeId = '.servicenow'; export const JIRA_ACTION_ID: ActionTypeId = '.jira'; export const WEBHOOK_ACTION_ID: ActionTypeId = '.webhook'; export const EMAIL_ACTION_ID: ActionTypeId = '.email'; +export const OPSGENIE_ACTION_ID: ActionTypeId = '.opsgenie'; export type RuleAction = Omit; @@ -128,6 +131,14 @@ export function populateAlertActions({ actions.push(recoveredAction); } break; + case OPSGENIE_ACTION_ID: + // @ts-expect-error + action.params = getOpsgenieActionParams(translations); + // @ts-expect-error + recoveredAction.params = getOpsgenieActionParams(translations, true); + actions.push(recoveredAction); + break; + default: action.params = { message: translations.defaultActionMessage, @@ -293,3 +304,24 @@ function getEmailActionParams( }, }; } + +function getOpsgenieActionParams( + { + defaultActionMessage, + defaultSubjectMessage, + defaultRecoverySubjectMessage, + defaultRecoveryMessage, + }: Translations, + isRecovery?: boolean +): OpsgenieActionParams { + return { + subAction: isRecovery ? OpsgenieSubActions.CloseAlert : OpsgenieSubActions.CreateAlert, + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + tags: ['{{rule.tags}}'], + message: isRecovery ? defaultRecoverySubjectMessage : defaultSubjectMessage, + description: isRecovery ? defaultRecoveryMessage : defaultActionMessage, + priority: 'P2', + }, + } as OpsgenieActionParams; +} diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts index a1888a100c178..0186bc8dc5252 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts @@ -16,6 +16,7 @@ import type { TeamsConnectorTypeId, WebhookConnectorTypeId, EmailConnectorTypeId, + OpsgenieConnectorTypeId, } from '@kbn/stack-connectors-plugin/server/connector_types'; import type { ActionConnector as RawActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; @@ -31,6 +32,7 @@ export type ActionTypeId = | typeof ServiceNowConnectorTypeId | typeof JiraConnectorTypeId | typeof WebhookConnectorTypeId - | typeof EmailConnectorTypeId; + | typeof EmailConnectorTypeId + | typeof OpsgenieConnectorTypeId; export type ActionConnector = Omit & { config?: SlackApiConfig }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx index 83b37f080d422..df311819399f3 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx @@ -67,6 +67,7 @@ export const getStatsOverviewEmbeddableFactory = ( i18n.translate('xpack.synthetics.editSloOverviewEmbeddableTitle.typeDisplayName', { defaultMessage: 'filters', }), + isEditingEnabled: () => true, onEdit: async () => { try { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx index a4e653bb1ddb0..eb97a0d5f3962 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx @@ -9,8 +9,7 @@ import { useDispatch, useSelector } from 'react-redux'; import React, { useEffect } from 'react'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { AlertTlsComponent } from './alert_tls'; -import { getDynamicSettings } from '../../state/settings/api'; -import { selectDynamicSettings } from '../../state/settings'; +import { getDynamicSettingsAction, selectDynamicSettings } from '../../state/settings'; import { TLSParams } from '../../../../../common/runtime_types/alerts/tls'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../common/constants'; @@ -24,7 +23,7 @@ export const TLSRuleComponent: React.FC<{ useEffect(() => { if (typeof settings === 'undefined') { - dispatch(getDynamicSettings()); + dispatch(getDynamicSettingsAction.get()); } }, [dispatch, settings]); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx index 65b9732e217e9..4bc09bc9884d0 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx @@ -33,15 +33,21 @@ export const FleetPermissionsCallout = () => { export const NoPermissionsTooltip = ({ canEditSynthetics = true, canUsePublicLocations = true, + canManagePrivateLocations = true, children, }: { canEditSynthetics?: boolean; canUsePublicLocations?: boolean; + canManagePrivateLocations?: boolean; children: ReactNode; }) => { const { isServiceAllowed } = useEnablement(); - const disabledMessage = getRestrictionReasonLabel(canEditSynthetics, canUsePublicLocations); + const disabledMessage = getRestrictionReasonLabel( + canEditSynthetics, + canUsePublicLocations, + canManagePrivateLocations + ); if (!isServiceAllowed) { return ( @@ -64,13 +70,18 @@ export const NoPermissionsTooltip = ({ function getRestrictionReasonLabel( canEditSynthetics = true, - canUsePublicLocations = true + canUsePublicLocations = true, + canManagePrivateLocations = true ): string | undefined { const message = !canEditSynthetics ? CANNOT_PERFORM_ACTION_SYNTHETICS : undefined; if (message) { return message; } + if (!canManagePrivateLocations) { + return NEED_PERMISSIONS_PRIVATE_LOCATIONS; + } + return !canUsePublicLocations ? CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS : undefined; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts index f81601e3ed413..ee00905ec7bd7 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts @@ -6,7 +6,10 @@ */ import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { + AlertConsumers, + SYNTHETICS_RULE_TYPE_IDS, +} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useFetcher } from '@kbn/observability-shared-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useParams } from 'react-router-dom'; @@ -25,7 +28,8 @@ export function useFetchActiveAlerts() { const { loading, data } = useFetcher(async () => { return await http.post(`${BASE_RAC_ALERTS_API_PATH}/find`, { body: JSON.stringify({ - feature_ids: [AlertConsumers.UPTIME], + rule_type_ids: SYNTHETICS_RULE_TYPE_IDS, + consumers: [AlertConsumers.UPTIME, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], size: 0, track_total_hits: true, query: { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx index 1737aa21b27d2..cb071a877d6ee 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, SYNTHETICS_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useParams } from 'react-router-dom'; import { useRefreshedRangeFromUrl } from '../../../hooks'; @@ -44,7 +44,8 @@ export function MonitorDetailsAlerts() { configurationId={AlertConsumers.OBSERVABILITY} id={MONITOR_ALERTS_TABLE_ID} data-test-subj="monitorAlertsTable" - featureIds={[AlertConsumers.UPTIME]} + ruleTypeIds={SYNTHETICS_RULE_TYPE_IDS} + consumers={[AlertConsumers.UPTIME, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} query={{ bool: { filter: [ diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts index c75bc5e489208..03c2c2ace9210 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts @@ -41,10 +41,6 @@ export function useCreateSLO({ tags: [], }, }, - budgetingMethod: 'occurrences', - objective: { - target: 0.99, - }, tags: tags || [], groupBy: ['monitor.name', 'observer.geo.name', 'monitor.id'], }, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx index 8f8fe31a638cf..ac6b471c9046f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx @@ -52,7 +52,7 @@ export const PrivateLocationsTable = ({ const { locationMonitors, loading } = useLocationMonitors(); - const { canSave } = useSyntheticsSettingsContext(); + const { canSave, canManagePrivateLocations } = useSyntheticsSettingsContext(); const tagsList = privateLocations.reduce((acc, item) => { const tags = item.tags || []; @@ -128,13 +128,16 @@ export const PrivateLocationsTable = ({ const renderToolRight = () => { return [ - + setIsAddingNew(true)} iconType="plusInCircle" > diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx index 24c32569f1f2a..5cabd6cf13742 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx @@ -119,6 +119,7 @@ describe('', () => { const privateLocationName = 'Test private location'; jest.spyOn(settingsHooks, 'useSyntheticsSettingsContext').mockReturnValue({ canSave, + canManagePrivateLocations: true, } as SyntheticsSettingsContextValues); jest.spyOn(locationHooks, 'usePrivateLocationsAPI').mockReturnValue({ diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx index d380d95c90aa4..518920ee0fd52 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx @@ -45,6 +45,7 @@ export interface SyntheticsAppProps { export interface SyntheticsSettingsContextValues { canSave: boolean; + canManagePrivateLocations: boolean; basePath: string; dateRangeStart: string; dateRangeEnd: string; @@ -74,6 +75,7 @@ const defaultContext: SyntheticsSettingsContextValues = { isLogsAvailable: true, isDev: false, canSave: false, + canManagePrivateLocations: false, }; export const SyntheticsSettingsContext = createContext(defaultContext); @@ -96,6 +98,8 @@ export const SyntheticsSettingsContextProvider: React.FC { return { @@ -109,6 +113,7 @@ export const SyntheticsSettingsContextProvider: React.FC; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx index c97cefc194069..687c2e833151d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx @@ -63,6 +63,7 @@ describe('useBreadcrumbs', () => { setBreadcrumbs: core.chrome.setBreadcrumbs, isInfraAvailable: false, isLogsAvailable: false, + canManagePrivateLocations: false, }} > diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx index 794747853642c..7c8824a8d56c9 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { ALERT_REASON, SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import type { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; @@ -15,7 +15,6 @@ import { getSyntheticsErrorRouteFromMonitorId } from '../../../../../common/util import { STATE_ID } from '../../../../../common/field_names'; import { SyntheticsMonitorStatusTranslations } from '../../../../../common/rules/synthetics/translations'; import type { StatusRuleParams } from '../../../../../common/rules/status_rule'; -import { SYNTHETICS_ALERT_RULE_TYPES } from '../../../../../common/constants/synthetics_alerts'; import type { AlertTypeInitializer } from './types'; const { defaultActionMessage, defaultRecoveryMessage, description } = diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx index 896a84cd1688c..10c45ece27a9f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx @@ -6,13 +6,12 @@ */ import React from 'react'; -import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { ALERT_REASON, SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public'; import { TlsTranslations } from '../../../../../common/rules/synthetics/translations'; import { CERTIFICATES_ROUTE } from '../../../../../common/constants/ui'; -import { SYNTHETICS_ALERT_RULE_TYPES } from '../../../../../common/constants/synthetics_alerts'; import type { TLSParams } from '../../../../../common/runtime_types/alerts/tls'; import type { AlertTypeInitializer } from './types'; diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts index ff4516a861225..1e3f8bf35e06b 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts @@ -10,16 +10,14 @@ import { isEmpty } from 'lodash'; import { GetViewInAppRelativeUrlFnOpts, AlertsClientError } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import apm from 'elastic-apm-node'; +import { SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { AlertOverviewStatus } from '../../../common/runtime_types/alert_rules/common'; import { StatusRuleExecutorOptions } from './types'; import { syntheticsRuleFieldMap } from '../../../common/rules/synthetics_rule_field_map'; import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../../types'; import { StatusRuleExecutor } from './status_rule_executor'; import { StatusRulePramsSchema } from '../../../common/rules/status_rule'; -import { - MONITOR_STATUS, - SYNTHETICS_ALERT_RULE_TYPES, -} from '../../../common/constants/synthetics_alerts'; +import { MONITOR_STATUS } from '../../../common/constants/synthetics_alerts'; import { setRecoveredAlertsContext, updateState, diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts index 5f8fc43c5d91c..111d590a4fd76 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts @@ -14,6 +14,7 @@ import { AlertsClientError, } from '@kbn/alerting-plugin/server'; import { asyncForEach } from '@kbn/std'; +import { SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { getAlertDetailsUrl, observabilityPaths } from '@kbn/observability-plugin/common'; import { schema } from '@kbn/config-schema'; import { ObservabilityUptimeAlert } from '@kbn/alerts-as-data-utils'; @@ -22,10 +23,7 @@ import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../.. import { getCertSummary, getTLSAlertDocument, setTLSRecoveredAlertsContext } from './message_utils'; import { SyntheticsCommonState } from '../../../common/runtime_types/alert_rules/common'; import { TLSRuleExecutor } from './tls_rule_executor'; -import { - SYNTHETICS_ALERT_RULE_TYPES, - TLS_CERTIFICATE, -} from '../../../common/constants/synthetics_alerts'; +import { TLS_CERTIFICATE } from '../../../common/constants/synthetics_alerts'; import { SyntheticsRuleTypeAlertDefinition, updateState } from '../common'; import { ALERT_DETAILS_URL, getActionVariables } from '../action_variables'; import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; diff --git a/x-pack/plugins/observability_solution/synthetics/server/feature.ts b/x-pack/plugins/observability_solution/synthetics/server/feature.ts index 5a4c4d508853b..0e8a08e8aed13 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/feature.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/feature.ts @@ -11,9 +11,10 @@ import { SubFeaturePrivilegeGroupConfig, SubFeaturePrivilegeGroupType, } from '@kbn/features-plugin/common'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; +import { UPTIME_RULE_TYPE_IDS, SYNTHETICS_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { syntheticsMonitorType, syntheticsParamType } from '../common/types/saved_objects'; -import { SYNTHETICS_RULE_TYPES } from '../common/constants/synthetics_alerts'; import { legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName, @@ -25,22 +26,22 @@ import { } from './saved_objects/synthetics_settings'; import { syntheticsApiKeyObjectType } from './saved_objects/service_api_key'; -const UPTIME_RULE_TYPES = [ - 'xpack.uptime.alerts.tls', - 'xpack.uptime.alerts.tlsCertificate', - 'xpack.uptime.alerts.monitorStatus', - 'xpack.uptime.alerts.durationAnomaly', -]; +export const PRIVATE_LOCATION_WRITE_API = 'private-location-write'; -const ruleTypes = [...UPTIME_RULE_TYPES, ...SYNTHETICS_RULE_TYPES]; +const ruleTypes = [...UPTIME_RULE_TYPE_IDS, ...SYNTHETICS_RULE_TYPE_IDS]; + +const alertingFeatures = ruleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN.ID, ALERTING_FEATURE_ID], +})); const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = { groupType: 'independent' as SubFeaturePrivilegeGroupType, privileges: [ { id: 'elastic_managed_locations_enabled', - name: i18n.translate('xpack.synthetics.features.elasticManagedLocations', { - defaultMessage: 'Elastic managed locations enabled', + name: i18n.translate('xpack.synthetics.features.elasticManagedLocations.label', { + defaultMessage: 'Enabled', }), includeIn: 'all', savedObject: { @@ -52,6 +53,25 @@ const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = ], }; +const canManagePrivateLocationsPrivilege: SubFeaturePrivilegeGroupConfig = { + groupType: 'independent' as SubFeaturePrivilegeGroupType, + privileges: [ + { + id: 'can_manage_private_locations', + name: i18n.translate('xpack.synthetics.features.canManagePrivateLocations', { + defaultMessage: 'Can manage', + }), + includeIn: 'all', + api: [PRIVATE_LOCATION_WRITE_API], + savedObject: { + all: [privateLocationSavedObjectName, legacyPrivateLocationsSavedObjectName], + read: [], + }, + ui: ['canManagePrivateLocations'], + }, + ], +}; + export const syntheticsFeature = { id: PLUGIN.ID, name: PLUGIN.NAME, @@ -63,7 +83,7 @@ export const syntheticsFeature = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: ruleTypes, + alerting: alertingFeatures, privileges: { all: { app: ['uptime', 'kibana', 'synthetics'], @@ -74,20 +94,19 @@ export const syntheticsFeature = { syntheticsSettingsObjectType, syntheticsMonitorType, syntheticsApiKeyObjectType, - privateLocationSavedObjectName, - legacyPrivateLocationsSavedObjectName, syntheticsParamType, + // uptime settings object is also registered here since feature is shared between synthetics and uptime uptimeSettingsObjectType, ], - read: [], + read: [privateLocationSavedObjectName, legacyPrivateLocationsSavedObjectName], }, alerting: { rule: { - all: ruleTypes, + all: alertingFeatures, }, alert: { - all: ruleTypes, + all: alertingFeatures, }, }, management: { @@ -114,10 +133,10 @@ export const syntheticsFeature = { }, alerting: { rule: { - read: ruleTypes, + read: alertingFeatures, }, alert: { - read: ruleTypes, + read: alertingFeatures, }, }, management: { @@ -128,10 +147,24 @@ export const syntheticsFeature = { }, subFeatures: [ { - name: i18n.translate('xpack.synthetics.features.app', { - defaultMessage: 'Synthetics', + name: i18n.translate('xpack.synthetics.features.app.elastic', { + defaultMessage: 'Elastic managed locations', + }), + description: i18n.translate('xpack.synthetics.features.app.elasticDescription', { + defaultMessage: + 'This feature enables users to create monitors that execute tests from Elastic managed infrastructure around the globe. There is an additional charge to use Elastic Managed testing locations. See the Elastic Cloud Pricing https://www.elastic.co/pricing page for current prices.', }), privilegeGroups: [elasticManagedLocationsEnabledPrivilege], }, + { + name: i18n.translate('xpack.synthetics.features.app.private', { + defaultMessage: 'Private locations', + }), + description: i18n.translate('xpack.synthetics.features.app.private,description', { + defaultMessage: + 'This feature allows you to manage your private locations, for example adding, or deleting them.', + }), + privilegeGroups: [canManagePrivateLocationsPrivilege], + }, ], }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/lib.ts b/x-pack/plugins/observability_solution/synthetics/server/lib.ts index 94150c0fb8ee5..8a703e1c051e8 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/lib.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/lib.ts @@ -158,7 +158,7 @@ export class SyntheticsEsClient { esError, esRequestParams: { index: SYNTHETICS_INDEX_PATTERN, ...request }, esRequestStatus: RequestStatus.OK, - esResponse: res.body.responses[index], + esResponse: res?.body.responses[index], kibanaRequest: this.request!, operationName: operationName ?? '', startTime: startTimeNow, @@ -168,9 +168,10 @@ export class SyntheticsEsClient { } return { - responses: res.body?.responses as unknown as Array< - InferSearchResponseOf - >, + responses: + (res?.body?.responses as unknown as Array< + InferSearchResponseOf + >) ?? [], }; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts index 2e2263f6e3965..d13395a42ca1a 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts @@ -99,7 +99,7 @@ export class DefaultAlertService { } async getExistingAlert(ruleType: DefaultRuleType) { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const { data } = await rulesClient.find({ options: { @@ -123,7 +123,7 @@ export class DefaultAlertService { } const actions = await this.getAlertActions(ruleType); - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const { actions: actionsFromRules = [], systemActions = [], @@ -158,7 +158,7 @@ export class DefaultAlertService { minimumRuleInterval ); } else { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); await rulesClient.bulkDeleteRules({ filter: `alert.attributes.alertTypeId:"${SYNTHETICS_STATUS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, }); @@ -174,7 +174,7 @@ export class DefaultAlertService { minimumRuleInterval ); } else { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); await rulesClient.bulkDeleteRules({ filter: `alert.attributes.alertTypeId:"${SYNTHETICS_TLS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, }); @@ -182,7 +182,7 @@ export class DefaultAlertService { } async upsertDefaultAlert(ruleType: DefaultRuleType, name: string, interval: string) { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const alert = await this.getExistingAlert(ruleType); if (alert) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts index 8311a6407bf6a..db8fbdd661f76 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor_project.ts @@ -14,7 +14,7 @@ import { ProjectMonitor } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; import { ProjectMonitorFormatter } from '../../synthetics_service/project_monitor/project_monitor_formatter'; -const MAX_PAYLOAD_SIZE = 1048576 * 50; // 20MiB +const MAX_PAYLOAD_SIZE = 1048576 * 50; // 50MiB export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'PUT', diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts index d460b71037950..2b815313c79c9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts @@ -305,7 +305,7 @@ export const syncEditedMonitor = async ({ }; export const validatePermissions = async ( - { server, response, request }: RouteContext, + routeContext: RouteContext, monitorLocations: MonitorLocations ) => { const hasPublicLocations = monitorLocations?.some((loc) => loc.isServiceManaged); @@ -313,19 +313,26 @@ export const validatePermissions = async ( return; } - const elasticManagedLocationsEnabled = - Boolean( - ( - await server.coreStart?.capabilities.resolveCapabilities(request, { - capabilityPath: 'uptime.*', - }) - ).uptime.elasticManagedLocationsEnabled - ) ?? true; + const { elasticManagedLocationsEnabled } = await validateLocationPermissions(routeContext); if (!elasticManagedLocationsEnabled) { return ELASTIC_MANAGED_LOCATIONS_DISABLED; } }; +export const validateLocationPermissions = async ({ server, request }: RouteContext) => { + const uptimeFeature = await server.coreStart?.capabilities.resolveCapabilities(request, { + capabilityPath: 'uptime.*', + }); + const elasticManagedLocationsEnabled = + Boolean(uptimeFeature.uptime.elasticManagedLocationsEnabled) ?? true; + const canManagePrivateLocations = Boolean(uptimeFeature.uptime.canManagePrivateLocations) ?? true; + + return { + canManagePrivateLocations, + elasticManagedLocationsEnabled, + }; +}; + const getInvalidOriginError = (monitor: SyntheticsMonitor) => { return { body: { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts index 1feb120b2ea14..fa88de31e3ec8 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts @@ -6,6 +6,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { PRIVATE_LOCATION_WRITE_API } from '../../../feature'; import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; @@ -38,10 +39,12 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory { - await migrateLegacyPrivateLocations(routeContext); + const { response, request, savedObjectsClient, syntheticsMonitorClient, server } = routeContext; + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); - const { response, request, savedObjectsClient, syntheticsMonitorClient } = routeContext; + await migrateLegacyPrivateLocations(internalSOClient, server.logger); const location = request.body as PrivateLocationObject; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts index bac3907eac871..d01b255dd2b32 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { isEmpty } from 'lodash'; +import { PRIVATE_LOCATION_WRITE_API } from '../../../feature'; import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { getMonitorsByLocation } from './get_location_monitors'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; @@ -25,10 +26,13 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory { - await migrateLegacyPrivateLocations(routeContext); - const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext; + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); + + await migrateLegacyPrivateLocations(internalSOClient, server.logger); + const { locationId } = request.params as { locationId: string }; const { locations } = await getPrivateLocationsAndAgentPolicies( diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts index d884bba5c2b0a..90d2e861379ad 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts @@ -31,9 +31,11 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory< }, }, handler: async (routeContext) => { - await migrateLegacyPrivateLocations(routeContext); + const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext; + + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); + await migrateLegacyPrivateLocations(internalSOClient, server.logger); - const { savedObjectsClient, syntheticsMonitorClient, request, response } = routeContext; const { id } = request.params as { id?: string }; const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies( diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts index 2305853aab3f1..f1e3101523c23 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts @@ -6,42 +6,28 @@ */ import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; -import { SyntheticsServerSetup } from '../../../types'; -import { coreMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; -import { - type ISavedObjectsRepository, - SavedObjectsClientContract, -} from '@kbn/core-saved-objects-api-server'; +import { type ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { Logger } from '@kbn/logging'; describe('migrateLegacyPrivateLocations', () => { - let serverMock: SyntheticsServerSetup; - let savedObjectsClient: jest.Mocked; - let repositoryMock: ISavedObjectsRepository; + let loggerMockVal: Logger; + let repositoryMock: jest.Mocked; beforeEach(() => { - const coreStartMock = coreMock.createStart(); - serverMock = { - coreStart: coreStartMock, - logger: loggerMock.create(), - } as any; - savedObjectsClient = savedObjectsClientMock.create(); - repositoryMock = coreMock.createStart().savedObjects.createInternalRepository(); - - coreStartMock.savedObjects.createInternalRepository.mockReturnValue(repositoryMock); + repositoryMock = savedObjectsRepositoryMock.create(); + loggerMockVal = loggerMock.create(); }); it('should get the legacy private locations', async () => { - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: [{ id: '1', label: 'Location 1' }] }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(savedObjectsClient.get).toHaveBeenCalledWith( + expect(repositoryMock.get).toHaveBeenCalledWith( 'synthetics-privates-locations', 'synthetics-privates-locations-singleton' ); @@ -49,43 +35,36 @@ describe('migrateLegacyPrivateLocations', () => { it('should log and return if an error occurs while getting legacy private locations', async () => { const error = new Error('Get error'); - savedObjectsClient.get.mockRejectedValueOnce(error); - - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, + repositoryMock.get.mockResolvedValueOnce({ + attributes: { locations: [{ id: '1', label: 'Location 1' }] }, } as any); + repositoryMock.bulkCreate.mockRejectedValueOnce(error); + + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(serverMock.logger.error).toHaveBeenCalledWith( - `Error getting legacy private locations: ${error}` + expect(loggerMockVal.error).toHaveBeenCalledWith( + 'Error migrating legacy private locations: Error: Get error' ); - expect(repositoryMock.bulkCreate).not.toHaveBeenCalled(); }); it('should return if there are no legacy locations', async () => { - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: [] }, } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient: savedObjectsClientMock, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); expect(repositoryMock.bulkCreate).not.toHaveBeenCalled(); }); it('should bulk create new private locations if there are legacy locations', async () => { const legacyLocations = [{ id: '1', label: 'Location 1' }]; - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: legacyLocations }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); expect(repositoryMock.bulkCreate).toHaveBeenCalledWith( legacyLocations.map((location) => ({ @@ -100,17 +79,14 @@ describe('migrateLegacyPrivateLocations', () => { it('should delete legacy private locations if bulk create count matches', async () => { const legacyLocations = [{ id: '1', label: 'Location 1' }]; - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: legacyLocations }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(savedObjectsClient.delete).toHaveBeenCalledWith( + expect(repositoryMock.delete).toHaveBeenCalledWith( 'synthetics-privates-locations', 'synthetics-privates-locations-singleton', {} diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts index cd73e27b950e3..e823e7764f540 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts @@ -6,6 +6,8 @@ */ import { SavedObject } from '@kbn/core-saved-objects-server'; +import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { Logger } from '@kbn/logging'; import { type PrivateLocationAttributes, SyntheticsPrivateLocationsAttributes, @@ -15,21 +17,20 @@ import { legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName, } from '../../../../common/saved_objects/private_locations'; -import { RouteContext } from '../../types'; -export const migrateLegacyPrivateLocations = async ({ - server, - savedObjectsClient, -}: RouteContext) => { +export const migrateLegacyPrivateLocations = async ( + soClient: ISavedObjectsRepository, + logger: Logger +) => { try { let obj: SavedObject | undefined; try { - obj = await savedObjectsClient.get( + obj = await soClient.get( legacyPrivateLocationsSavedObjectName, legacyPrivateLocationsSavedObjectId ); } catch (e) { - server.logger.error(`Error getting legacy private locations: ${e}`); + // we don't need to do anything if the legacy object doesn't exist return; } const legacyLocations = obj?.attributes.locations ?? []; @@ -37,8 +38,6 @@ export const migrateLegacyPrivateLocations = async ({ return; } - const soClient = server.coreStart.savedObjects.createInternalRepository(); - await soClient.bulkCreate( legacyLocations.map((location) => ({ id: location.id, @@ -51,20 +50,21 @@ export const migrateLegacyPrivateLocations = async ({ } ); - const { total } = await savedObjectsClient.find({ + const { total } = await soClient.find({ type: privateLocationSavedObjectName, fields: [], perPage: 0, + namespaces: ['*'], }); if (total === legacyLocations.length) { - await savedObjectsClient.delete( + await soClient.delete( legacyPrivateLocationsSavedObjectName, legacyPrivateLocationsSavedObjectId, {} ); } } catch (e) { - server.logger.error(`Error migrating legacy private locations: ${e}`); + logger.error(`Error migrating legacy private locations: ${e}`); } }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts index fa481d16b92bf..837197d72d23a 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts @@ -38,6 +38,7 @@ export type SupportedMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; export interface UMServerRoute { method: SupportedMethod; writeAccess?: boolean; + requiredPrivileges?: string[]; handler: T; validation?: VersionedRouteValidation; streamHandler?: ( diff --git a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts index f695662e811e3..b7eaea482db92 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts @@ -21,6 +21,7 @@ export const PrivateLocationAttributesCodec = t.intersection([ lon: t.number, }), namespace: t.string, + spaces: t.array(t.string), }), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts index 697cf93d74213..da3887ac94d56 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts @@ -24,7 +24,11 @@ export const syntheticsRouteWrapper: SyntheticsRouteWrapper = ( }, security: { authz: { - requiredPrivileges: ['uptime-read', ...(uptimeRoute?.writeAccess ? ['uptime-write'] : [])], + requiredPrivileges: [ + 'uptime-read', + ...(uptimeRoute.requiredPrivileges ?? []), + ...(uptimeRoute?.writeAccess ? ['uptime-write'] : []), + ], }, }, handler: async (context, request, response) => { diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.test.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.test.ts index 93b3ca2fb3742..cab8157ca3567 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.test.ts @@ -470,6 +470,61 @@ describe('callAPI', () => { url: 'https://service.dev/monitors/sync', }); }); + + it('splits the payload into multiple requests if the payload is too large', async () => { + const requests: number[] = []; + const axiosSpy = (axios as jest.MockedFunction).mockImplementation((req: any) => { + requests.push(req.data.monitors.length); + if (req.data.monitors.length > 100) { + // throw 413 error + return Promise.reject({ response: { status: 413 } }); + } + + return Promise.resolve({} as any); + }); + + const apiClient = new ServiceAPIClient( + logger, + { + manifestUrl: 'http://localhost:8080/api/manifest', + tls: { certificate: 'test-certificate', key: 'test-key' } as any, + }, + { + isDev: true, + stackVersion: '8.7.0', + cloud: { cloudId: 'test-id', deploymentId: 'deployment-id' }, + } as SyntheticsServerSetup + ); + + apiClient.locations = testLocations; + + const output = { hosts: ['https://localhost:9200'], api_key: '12345' }; + + const monitors = new Array(250).fill({ + ...request1[0], + locations: [ + { + id: 'us_central', + isServiceManaged: true, + }, + ], + }); + + await apiClient.syncMonitors({ + monitors, + output, + license: licenseMock.license, + location: { + id: 'us_central', + url: 'https://service.dev', + label: 'Test location', + isServiceManaged: true, + }, + }); + + expect(axiosSpy).toHaveBeenCalledTimes(7); + expect(requests).toEqual([250, 125, 125, 63, 62, 63, 62]); + }); }); const testLocations: PublicLocations = [ diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts index 73f286e40d310..3f9959440b3e9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts @@ -6,7 +6,7 @@ */ import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { forkJoin, from as rxjsFrom, Observable, of } from 'rxjs'; +import { concat, forkJoin, from as rxjsFrom, Observable, of } from 'rxjs'; import { catchError, tap } from 'rxjs'; import * as https from 'https'; import { SslConfig } from '@kbn/server-http-tools'; @@ -215,21 +215,47 @@ export class ServiceAPIClient { const monitorsByLocation = this.processServiceData(serviceData); - monitorsByLocation.forEach(({ location: { url, id }, monitors, data }) => { - const promise = this.callServiceEndpoint(data, method, url, endpoint); - promises.push( - rxjsFrom(promise).pipe( + monitorsByLocation.forEach(({ location: { url, id }, data }) => { + const sendRequest = (payload: ServicePayload): Observable => { + const promise = this.callServiceEndpoint(payload, method, url, endpoint); + return rxjsFrom(promise).pipe( tap((result) => { - this.logSuccessMessage(url, method, monitors.length, result); + this.logSuccessMessage(url, method, payload.monitors.length, result); }), catchError((err: AxiosError<{ reason: string; status: number }>) => { + if (err.response?.status === 413 && payload.monitors.length > 1) { + // If payload is too large, split it and retry + const mid = Math.ceil(payload.monitors.length / 2); + const firstHalfMonitors = payload.monitors.slice(0, mid); + const secondHalfMonitors = payload.monitors.slice(mid); + + this.logger.debug( + `Payload of ${payload.monitors.length} monitors is too large for location ${id}, splitting in half, in chunks of ${mid}` + ); + + return concat( + sendRequest({ + ...payload, + monitors: firstHalfMonitors, + }), // Retry with the first half + sendRequest({ + ...payload, + monitors: secondHalfMonitors, + }) // Retry with the second half + ); + } + pushErrors.push({ locationId: id, error: err.response?.data! }); - this.logServiceError(err, url, method, monitors.length); - // we don't want to throw an unhandled exception here + this.logServiceError(err, url, method, payload.monitors.length); + + // Return an empty observable to prevent unhandled exceptions return of(true); }) - ) - ); + ); + }; + + // Start with the initial data payload + promises.push(sendRequest(data)); }); const result = await forkJoin(promises).toPromise(); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.ts index be72ca4d9a496..c223de84c42dc 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.ts @@ -152,7 +152,9 @@ export class SyntheticsService { service.locations = result.locations; service.apiClient.locations = result.locations; this.logger.debug( - `Fetched ${service.locations} Synthetics service locations from manifest: ${this.config.manifestUrl}` + `Fetched ${service.locations + .map((loc) => loc.id) + .join(',')} Synthetics service locations from manifest: ${this.config.manifestUrl}` ); } catch (e) { this.logger.error(e); @@ -167,7 +169,7 @@ export class SyntheticsService { [SYNTHETICS_SERVICE_SYNC_MONITORS_TASK_TYPE]: { title: 'Synthetics Service - Sync Saved Monitors', description: 'This task periodically pushes saved monitors to Synthetics Service.', - timeout: '1m', + timeout: '2m', maxAttempts: 3, createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { @@ -670,10 +672,10 @@ export class SyntheticsService { if (lastRunAt) { // log if it has missed last schedule - const diff = moment(lastRunAt).diff(current, 'minutes'); + const diff = moment(current).diff(lastRunAt, 'minutes'); const syncInterval = Number((this.config.syncInterval ?? '5m').split('m')[0]); if (diff > syncInterval) { - const message = `Synthetics monitor sync task has missed its schedule, it last ran ${diff} ago.`; + const message = `Synthetics monitor sync task has missed its schedule, it last ran ${diff} minutes ago.`; this.logger.warn(message); sendErrorTelemetryEvents(this.logger, this.server.telemetry, { message, @@ -681,11 +683,8 @@ export class SyntheticsService { type: 'syncTaskMissedSchedule', stackVersion: this.server.stackVersion, }); - } else { - this.logger.debug( - `Synthetics monitor sync task is running as expected, it last ran ${diff} minutes ago.` - ); } + this.logger.debug(`Synthetics monitor sync task last ran ${diff} minutes ago.`); } state.lastRunAt = current.toISOString(); } catch (e) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/types.ts b/x-pack/plugins/observability_solution/synthetics/server/types.ts index e024721101d1f..1a8016830c085 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/types.ts @@ -17,10 +17,7 @@ import { Logger, SavedObjectsClientContract, } from '@kbn/core/server'; -import { - PluginStartContract as AlertingPluginStart, - PluginSetupContract as AlertingPluginSetup, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { SharePluginSetup } from '@kbn/share-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; @@ -62,14 +59,14 @@ export interface SyntheticsServerSetup { basePath: IBasePath; isDev?: boolean; coreStart: CoreStart; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; pluginsStart: SyntheticsPluginsStartDependencies; isElasticsearchServerless: boolean; } export interface SyntheticsPluginsSetupDependencies { features: FeaturesPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; observability: ObservabilityPluginSetup; usageCollection: UsageCollectionSetup; ml: MlSetup; @@ -90,7 +87,7 @@ export interface SyntheticsPluginsStartDependencies { taskManager: TaskManagerStartContract; telemetry: TelemetryPluginStart; spaces?: SpacesPluginStart; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; } export type UptimeRequestHandlerContext = CustomRequestHandlerContext<{ diff --git a/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts b/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts index 223b8909de96e..5de01b708ea2c 100644 --- a/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts +++ b/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts @@ -42,6 +42,4 @@ export const SYNTHETICS_ALERT_RULE_TYPES = { TLS: SYNTHETICS_TLS_RULE, }; -export const SYNTHETICS_RULE_TYPES = [SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE]; - export const SYNTHETICS_RULE_TYPES_ALERT_CONTEXT = 'observability.uptime'; diff --git a/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts b/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts index 71f6bd1b183fb..1a84cf461b3e4 100644 --- a/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts +++ b/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts @@ -41,9 +41,4 @@ export const CLIENT_ALERT_TYPES = { DURATION_ANOMALY: 'xpack.uptime.alerts.durationAnomaly', }; -export const UPTIME_RULE_TYPES = [ - 'xpack.uptime.alerts.tls', - 'xpack.uptime.alerts.tlsCertificate', - 'xpack.uptime.alerts.monitorStatus', - 'xpack.uptime.alerts.durationAnomaly', -]; +export { UPTIME_RULE_TYPE_IDS as UPTIME_RULE_TYPES } from '@kbn/rule-data-utils'; diff --git a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts index 357d008c4b901..9cfc38b8730cc 100644 --- a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts +++ b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts @@ -23,7 +23,7 @@ export const createGetMonitorDetailsRoute: UMRestApiRouteFactory = (libs: UMServ handler: async ({ uptimeEsClient, context, request }): Promise => { const { monitorId, dateStart, dateEnd } = request.query; - const rulesClient = (await context.alerting)?.getRulesClient(); + const rulesClient = await (await context.alerting)?.getRulesClient(); return await libs.requests.getMonitorDetails({ uptimeEsClient, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts index 66ef6a73013f4..d58d5398f907c 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts @@ -20,7 +20,6 @@ const createAlertsClientMock = () => { bulkUpdateCases: jest.fn(), find: jest.fn(), getGroupAggregations: jest.fn(), - getFeatureIdsByRegistrationContexts: jest.fn(), getBrowserFields: jest.fn(), getAlertSummary: jest.fn(), ensureAllAlertsAuthorizedRead: jest.fn(), diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts new file mode 100644 index 0000000000000..77215955277dc --- /dev/null +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts @@ -0,0 +1,244 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { ruleDataServiceMock } from '../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { AlertsClient, ConstructorOptions } from './alerts_client'; +import { fromKueryExpression } from '@kbn/es-query'; + +describe('AlertsClient', () => { + const alertingAuthMock = alertingAuthorizationMock.create(); + const ruleDataService = ruleDataServiceMock.create(); + const requestHandlerContext = coreMock.createRequestHandlerContext(); + const esClientMock = requestHandlerContext.elasticsearch.client.asCurrentUser; + + let alertsClient: AlertsClient; + + beforeEach(() => { + jest.clearAllMocks(); + alertingAuthMock.getSpaceId.mockReturnValue('space-1'); + alertingAuthMock.getAllAuthorizedRuleTypesFindOperation.mockResolvedValue( + new Map([ + [ + 'test-rule-type-1', + { + id: 'test-rule-type-1', + authorizedConsumers: { foo: { all: true, read: true } }, + }, + ], + ]) + ); + + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: fromKueryExpression( + 'alert.attributes.alertTypeId: test-rule-type-1 AND alert.attributes.consumer: foo' + ), + ensureRuleTypeIsAuthorized: jest.fn(), + }); + + const alertsClientParams: ConstructorOptions = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + ruleDataService, + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn(), + }; + + alertsClient = new AlertsClient(alertsClientParams); + }); + + describe('find', () => { + it('creates the ruleTypeIds filter correctly', async () => { + await alertsClient.find({ ruleTypeIds: ['test-rule-type-1', 'test-rule-type-2'] }); + + expect(esClientMock.search.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "_source": undefined, + "aggs": undefined, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "test-rule-type-1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + Object { + "term": Object { + "kibana.space_ids": "space-1", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "test-rule-type-1", + "test-rule-type-2", + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": undefined, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": ".alerts-*", + "seq_no_primary_term": true, + } + `); + }); + + it('creates the consumers filter correctly', async () => { + await alertsClient.find({ consumers: ['test-consumer-1', 'test-consumer-2'] }); + + expect(esClientMock.search.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "_source": undefined, + "aggs": undefined, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "test-rule-type-1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + Object { + "term": Object { + "kibana.space_ids": "space-1", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "test-consumer-1", + "test-consumer-2", + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": undefined, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": ".alerts-*", + "seq_no_primary_term": true, + } + `); + }); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index ea80a365ccd95..3a898b07fb461 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -15,29 +15,23 @@ import { ALERT_STATUS, getEsQueryConfig, getSafeSortIds, - isValidFeatureId, STATUS_VALUES, - ValidFeatureId, ALERT_STATUS_RECOVERED, ALERT_END, ALERT_STATUS_ACTIVE, ALERT_CASE_IDS, MAX_CASES_PER_ALERT, - AlertConsumers, + isSiemRuleType, } from '@kbn/rule-data-utils'; import { AggregateName, AggregationsAggregate, - AggregationsMultiBucketAggregateBase, MappingRuntimeFields, QueryDslQueryContainer, SortCombinations, } from '@elastic/elasticsearch/lib/api/types'; -import type { - RuleTypeParams, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import type { RuleTypeParams, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { ReadOperations, AlertingAuthorization, @@ -68,6 +62,8 @@ import { MAX_ALERTS_PAGES, MAX_PAGINATED_ALERTS, } from './constants'; +import { getRuleTypeIdsFilter } from '../lib/get_rule_type_ids_filter'; +import { getConsumersFilter } from '../lib/get_consumers_filter'; // TODO: Fix typings https://github.com/elastic/kibana/issues/101776 type NonNullableProps = Omit & { @@ -97,7 +93,7 @@ export interface ConstructorOptions { ruleDataService: IRuleDataService; getRuleType: RuleTypeRegistry['get']; getRuleList: RuleTypeRegistry['list']; - getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; + getAlertIndicesAlias: AlertingServerStart['getAlertIndicesAlias']; } export interface UpdateOptions { @@ -138,7 +134,8 @@ interface GetAlertSummaryParams { id?: string; gte: string; lte: string; - featureIds: string[]; + ruleTypeIds: string[]; + consumers?: string[]; filter?: estypes.QueryDslQueryContainer[]; fixedInterval?: string; } @@ -154,7 +151,8 @@ interface SearchAlertsParams { operation: WriteOperations.Update | ReadOperations.Find | ReadOperations.Get; sort?: estypes.SortOptions[]; lastSortIds?: Array; - featureIds?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; runtimeMappings?: MappingRuntimeFields; } @@ -172,7 +170,7 @@ export class AlertsClient { private readonly ruleDataService: IRuleDataService; private readonly getRuleType: RuleTypeRegistry['get']; private readonly getRuleList: RuleTypeRegistry['list']; - private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; + private getAlertIndicesAlias!: AlertingServerStart['getAlertIndicesAlias']; constructor(options: ConstructorOptions) { this.logger = options.logger; @@ -295,7 +293,8 @@ export class AlertsClient { operation, sort, lastSortIds = [], - featureIds, + ruleTypeIds, + consumers, runtimeMappings, }: SearchAlertsParams) { try { @@ -316,7 +315,8 @@ export class AlertsClient { alertSpaceId, operation, config, - featureIds ? new Set(featureIds) : undefined + ruleTypeIds, + consumers ), aggs, _source, @@ -372,7 +372,9 @@ export class AlertsClient { return result; } catch (error) { - const errorMessage = `Unable to retrieve alert details for alert with id of "${id}" or with query "${query}" and operation ${operation} \nError: ${error}`; + const errorMessage = `Unable to retrieve alert details for alert with id of "${id}" or with query "${JSON.stringify( + query + )}" and operation ${operation} \nError: ${error}`; this.logger.error(errorMessage); throw Boom.notFound(errorMessage); } @@ -457,16 +459,17 @@ export class AlertsClient { alertSpaceId: string, operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find, config: EsQueryConfig, - featuresIds?: Set + ruleTypeIds?: string[], + consumers?: string[] ) { try { - const authzFilter = (await getAuthzFilter( - this.authorization, - operation, - featuresIds - )) as Filter; + const authzFilter = (await getAuthzFilter(this.authorization, operation)) as Filter; const spacesFilter = getSpacesFilter(alertSpaceId) as unknown as Filter; + const ruleTypeIdsFilter = getRuleTypeIdsFilter(ruleTypeIds) as unknown as Filter; + const consumersFilter = getConsumersFilter(consumers) as unknown as Filter; + let esQuery; + if (id != null) { esQuery = { query: `_id:${id}`, language: 'kuery' }; } else if (typeof query === 'string') { @@ -474,12 +477,14 @@ export class AlertsClient { } else if (query != null && typeof query === 'object') { esQuery = []; } + const builtQuery = buildEsQuery( undefined, esQuery == null ? { query: ``, language: 'kuery' } : esQuery, - [authzFilter, spacesFilter], + [authzFilter, spacesFilter, ruleTypeIdsFilter, consumersFilter], config ); + if (query != null && typeof query === 'object') { return { ...builtQuery, @@ -639,15 +644,16 @@ export class AlertsClient { public async getAlertSummary({ gte, lte, - featureIds, + ruleTypeIds, + consumers, filter, fixedInterval = '1m', }: GetAlertSummaryParams) { try { - const indexToUse = await this.getAuthorizedAlertsIndices(featureIds); + const indexToUse = await this.getAuthorizedAlertsIndices(ruleTypeIds); if (isEmpty(indexToUse)) { - throw Boom.badRequest('no featureIds were provided for getting alert summary'); + throw Boom.badRequest('no ruleTypeIds were provided for getting alert summary'); } // first search for the alert by id, then use the alert info to check if user has access to it @@ -710,7 +716,8 @@ export class AlertsClient { }, }, size: 0, - featureIds, + ruleTypeIds, + consumers, }); let activeAlertCount = 0; @@ -981,7 +988,8 @@ export class AlertsClient { TAggregations = Record >({ aggs, - featureIds, + ruleTypeIds, + consumers, index, query, search_after: searchAfter, @@ -992,7 +1000,8 @@ export class AlertsClient { runtimeMappings, }: { aggs?: object; - featureIds?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; index?: string; query?: object; search_after?: Array; @@ -1004,15 +1013,16 @@ export class AlertsClient { }) { try { let indexToUse = index; - if (featureIds && !isEmpty(featureIds)) { - const tempIndexToUse = await this.getAuthorizedAlertsIndices(featureIds); + if (ruleTypeIds && !isEmpty(ruleTypeIds)) { + const tempIndexToUse = await this.getAuthorizedAlertsIndices(ruleTypeIds); if (!isEmpty(tempIndexToUse)) { indexToUse = (tempIndexToUse ?? []).join(); } } const alertsSearchResponse = await this.searchAlerts({ - featureIds, + ruleTypeIds, + consumers, query, aggs, _source, @@ -1042,7 +1052,8 @@ export class AlertsClient { * Performs a `find` query to extract aggregations on alert groups */ public async getGroupAggregations({ - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -1051,9 +1062,15 @@ export class AlertsClient { sort = [{ unitsCount: { order: 'desc' } }], }: { /** - * The feature ids the alerts belong to, used for authorization + * The rule type IDs the alerts belong to. + * Used for filtering. + */ + ruleTypeIds: string[]; + /** + * The consumers the alerts belong to. + * Used for filtering. */ - featureIds: string[]; + consumers?: string[]; /** * The field to group by * @example "kibana.alert.rule.name" @@ -1093,9 +1110,10 @@ export class AlertsClient { } const searchResult = await this.find< never, - { groupByFields: AggregationsMultiBucketAggregateBase<{ key: string }> } + { groupByFields: estypes.AggregationsMultiBucketAggregateBase<{ key: string }> } >({ - featureIds, + ruleTypeIds, + consumers, aggs: { groupByFields: { terms: { @@ -1163,14 +1181,15 @@ export class AlertsClient { return searchResult; } - public async getAuthorizedAlertsIndices(featureIds: string[]): Promise { + public async getAuthorizedAlertsIndices(ruleTypeIds?: string[]): Promise { try { - const authorizedRuleTypes = await this.authorization.getAuthorizedRuleTypes( - AlertingAuthorizationEntity.Alert, - new Set(featureIds) - ); + const authorizedRuleTypes = await this.authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); + const indices = this.getAlertIndicesAlias( - authorizedRuleTypes.map((art: { id: any }) => art.id), + Array.from(authorizedRuleTypes.keys()).map((id) => id), this.spaceId ); @@ -1182,48 +1201,13 @@ export class AlertsClient { } } - public async getFeatureIdsByRegistrationContexts( - RegistrationContexts: string[] - ): Promise { - try { - const featureIds = - this.ruleDataService.findFeatureIdsByRegistrationContexts(RegistrationContexts); - if (featureIds.length > 0) { - // ATTENTION FUTURE DEVELOPER when you are a super user the augmentedRuleTypes.authorizedRuleTypes will - // return all of the features that you can access and does not care about your featureIds - const augmentedRuleTypes = await this.authorization.getAugmentedRuleTypesWithAuthorization( - featureIds, - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ); - // As long as the user can read a minimum of one type of rule type produced by the provided feature, - // the user should be provided that features' alerts index. - // Limiting which alerts that user can read on that index will be done via the findAuthorizationFilter - const authorizedFeatures = new Set(); - for (const ruleType of augmentedRuleTypes.authorizedRuleTypes) { - authorizedFeatures.add(ruleType.producer); - } - const validAuthorizedFeatures = Array.from(authorizedFeatures).filter( - (feature): feature is ValidFeatureId => - featureIds.includes(feature) && isValidFeatureId(feature) - ); - return validAuthorizedFeatures; - } - return featureIds; - } catch (exc) { - const errMessage = `getFeatureIdsByRegistrationContexts failed to get feature ids: ${exc}`; - this.logger.error(errMessage); - throw Boom.failedDependency(errMessage); - } - } - public async getBrowserFields({ - featureIds, + ruleTypeIds, indices, metaFields, allowNoIndex, }: { - featureIds: string[]; + ruleTypeIds: string[]; indices: string[]; metaFields: string[]; allowNoIndex: boolean; @@ -1231,13 +1215,15 @@ export class AlertsClient { const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); const ruleTypeList = this.getRuleList(); const fieldsForAAD = new Set(); - for (const rule of ruleTypeList) { - if (featureIds.includes(rule.producer) && rule.hasFieldsForAAD) { + + for (const rule of ruleTypeList.values()) { + if (ruleTypeIds.includes(rule.id) && rule.hasFieldsForAAD) { (rule.fieldsForAAD ?? []).forEach((f) => { fieldsForAAD.add(f); }); } } + const { fields } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ pattern: indices, metaFields, @@ -1252,11 +1238,12 @@ export class AlertsClient { } public async getAADFields({ ruleTypeId }: { ruleTypeId: string }) { - const { producer, fieldsForAAD = [] } = this.getRuleType(ruleTypeId); - if (producer === AlertConsumers.SIEM) { + const { fieldsForAAD = [] } = this.getRuleType(ruleTypeId); + if (isSiemRuleType(ruleTypeId)) { throw Boom.badRequest(`Security solution rule type is not supported`); } - const indices = await this.getAuthorizedAlertsIndices([producer]); + + const indices = await this.getAuthorizedAlertsIndices([ruleTypeId]); const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); const { fields = [] } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ pattern: indices ?? [], diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts index 367ead5744d55..8613f6135d30a 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts @@ -21,7 +21,7 @@ const alertingAuthMock = alertingAuthorizationMock.create(); const alertsClientFactoryParams: AlertsClientFactoryProps = { logger: loggingSystemMock.create().get(), - getAlertingAuthorization: (_: KibanaRequest) => alertingAuthMock, + getAlertingAuthorization: (_: KibanaRequest) => Promise.resolve(alertingAuthMock), securityPluginSetup, esClient: {} as ElasticsearchClient, ruleDataService: ruleDataServiceMock.create(), diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts index 934074cc4a2ed..91449954db61c 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts @@ -8,10 +8,7 @@ import { PublicMethodsOf } from '@kbn/utility-types'; import { ElasticsearchClient, KibanaRequest, Logger } from '@kbn/core/server'; import type { RuleTypeRegistry } from '@kbn/alerting-plugin/server/types'; -import { - AlertingAuthorization, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import { AlertingAuthorization, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { IRuleDataService } from '../rule_data_plugin_service'; import { AlertsClient } from './alerts_client'; @@ -19,12 +16,14 @@ import { AlertsClient } from './alerts_client'; export interface AlertsClientFactoryProps { logger: Logger; esClient: ElasticsearchClient; - getAlertingAuthorization: (request: KibanaRequest) => PublicMethodsOf; + getAlertingAuthorization: ( + request: KibanaRequest + ) => Promise>; securityPluginSetup: SecurityPluginSetup | undefined; ruleDataService: IRuleDataService | null; getRuleType: RuleTypeRegistry['get']; getRuleList: RuleTypeRegistry['list']; - getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; + getAlertIndicesAlias: AlertingServerStart['getAlertIndicesAlias']; } export class AlertsClientFactory { @@ -33,12 +32,12 @@ export class AlertsClientFactory { private esClient!: ElasticsearchClient; private getAlertingAuthorization!: ( request: KibanaRequest - ) => PublicMethodsOf; + ) => Promise>; private securityPluginSetup!: SecurityPluginSetup | undefined; private ruleDataService!: IRuleDataService | null; private getRuleType!: RuleTypeRegistry['get']; private getRuleList!: RuleTypeRegistry['list']; - private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; + private getAlertIndicesAlias!: AlertingServerStart['getAlertIndicesAlias']; public initialize(options: AlertsClientFactoryProps) { /** @@ -61,10 +60,11 @@ export class AlertsClientFactory { public async create(request: KibanaRequest): Promise { const { securityPluginSetup, getAlertingAuthorization, logger } = this; + const authorization = await getAlertingAuthorization(request); return new AlertsClient({ logger, - authorization: getAlertingAuthorization(request), + authorization, auditLogger: securityPluginSetup?.audit.asScoped(request), esClient: this.esClient, ruleDataService: this.ruleDataService!, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts index 28cd76ca6dffe..8d2e6cffa0cc5 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts @@ -17,7 +17,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -36,39 +35,38 @@ const alertsClientParams: jest.Mocked = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); - alertingAuthMock.getSpaceId.mockImplementation(() => 'test_default_space_id'); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, + }); + + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); const fakeAlertId = 'myfakeid1'; @@ -337,7 +335,7 @@ describe('bulkUpdate()', () => { }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "queryAndAuditAllAlerts threw an error: Unable to retrieve alerts with query \\"kibana.alert.status: active\\" and operation update - Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"kibana.alert.status: active\\" and operation update + Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"\\"kibana.alert.status: active\\"\\" and operation update Error: Error: Unauthorized for fake.rule and apm" `); @@ -404,7 +402,7 @@ describe('bulkUpdate()', () => { }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "queryAndAuditAllAlerts threw an error: Unable to retrieve alerts with query \\"kibana.alert.status: active\\" and operation update - Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"kibana.alert.status: active\\" and operation update + Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"\\"kibana.alert.status: active\\"\\" and operation update Error: Error: Unauthorized for fake.rule and apm" `); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts index 57e877f568cd9..c554ee4d61f99 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts @@ -16,62 +16,107 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { JsonObject } from '@kbn/utility-types'; -const alertingAuthMock = alertingAuthorizationMock.create(); -const esClientMock = elasticsearchClientMock.createElasticsearchClient(); -const auditLogger = auditLoggerMock.create(); +describe('find()', () => { + const alertingAuthMock = alertingAuthorizationMock.create(); + const esClientMock = elasticsearchClientMock.createElasticsearchClient(); + const auditLogger = auditLoggerMock.create(); -const alertsClientParams: jest.Mocked = { - logger: loggingSystemMock.create().get(), - authorization: alertingAuthMock, - esClient: esClientMock, - auditLogger, - ruleDataService: ruleDataServiceMock.create(), - getRuleType: jest.fn(), - getRuleList: jest.fn(), - getAlertIndicesAlias: jest.fn(), -}; + const alertsClientParams: jest.Mocked = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn(), + }; -const DEFAULT_SPACE = 'test_default_space_id'; + const DEFAULT_SPACE = 'test_default_space_id'; + const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], + ]); -beforeEach(() => { - jest.resetAllMocks(); - alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); - }); + const filter = { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + filter: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.rule_type_id': '.es-query' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'stackAlerts' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'alerts' } }], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, + }, + }, + { term: { 'kibana.space_ids': 'default' } }, + { terms: { 'kibana.alert.rule.rule_type_id': ['.es-query'] } }, + ], + }, + }; - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { + beforeEach(() => { + jest.resetAllMocks(); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: filter as unknown as JsonObject, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, + }); + + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { return Promise.resolve(); } return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); - } - ); -}); + }); + }); -describe('find()', () => { test('calls ES client with given params', async () => { const alertsClient = new AlertsClient(alertsClientParams); const searchAlertsSpy = jest.spyOn(alertsClient as any, 'searchAlerts'); @@ -111,19 +156,25 @@ describe('find()', () => { }); const query = { match: { [ALERT_WORKFLOW_STATUS]: 'open' } }; const index = '.alerts-observability.apm.alerts'; - const featureIds = ['siem']; + const ruleTypeIds = ['siem.esqlRule', 'siem.eqlRule']; + const consumers = ['siem']; + const result = await alertsClient.find({ query, index, - featureIds, + ruleTypeIds, + consumers, }); + expect(searchAlertsSpy).toHaveBeenCalledWith( expect.objectContaining({ query, index, - featureIds, + ruleTypeIds, + consumers, }) ); + expect(result).toMatchInlineSnapshot(` Object { "_shards": Object { @@ -176,12 +227,100 @@ describe('find()', () => { "query": Object { "bool": Object { "filter": Array [ - Object {}, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, Object { "term": Object { "kibana.space_ids": "test_default_space_id", }, }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + "siem.eqlRule", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "siem", + ], + }, + }, ], "must": Array [ Object { @@ -310,7 +449,80 @@ describe('find()', () => { "query": Object { "bool": Object { "filter": Array [ - Object {}, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, Object { "term": Object { "kibana.space_ids": "test_default_space_id", @@ -437,7 +649,7 @@ describe('find()', () => { index: '.alerts-observability.apm.alerts', }) ).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find + "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"{\\"match\\":{\\"kibana.alert.workflow_status\\":\\"open\\"}}\\" and operation find Error: Error: Unauthorized for fake.rule and apm" `); @@ -467,7 +679,7 @@ describe('find()', () => { index: '.alerts-observability.apm.alerts', }) ).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find + "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"{\\"match\\":{\\"kibana.alert.workflow_status\\":\\"open\\"}}\\" and operation find Error: Error: something went wrong" `); }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts index b48e68c3bf255..b0fcb505d95b6 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts @@ -17,7 +17,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -36,41 +35,38 @@ const alertsClientParams: jest.Mocked = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('get()', () => { @@ -150,7 +146,6 @@ describe('get()', () => { ], }, }, - Object {}, Object { "term": Object { "kibana.space_ids": "test_default_space_id", diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts index 777b3d3e26742..0a7b11e2be9b0 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsClient, ConstructorOptions } from '../alerts_client'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; @@ -38,13 +37,12 @@ beforeEach(() => { describe('getAADFields()', () => { test('should throw an error when a rule type belong to security solution', async () => { getRuleTypeMock.mockImplementation(() => ({ - producer: AlertConsumers.SIEM, fieldsForAAD: [], })); const alertsClient = new AlertsClient(alertsClientParams); await expect( - alertsClient.getAADFields({ ruleTypeId: 'security-type' }) + alertsClient.getAADFields({ ruleTypeId: 'siem.esqlRule' }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Security solution rule type is not supported"`); }); }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts index c351de1283c2b..2bcafffdeebab 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsClient, ConstructorOptions } from '../alerts_client'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; import { DEFAULT_ALERTS_GROUP_BY_FIELD_SIZE, MAX_ALERTS_GROUPING_QUERY_SIZE } from '../constants'; @@ -33,40 +31,38 @@ const alertsClientParams: jest.Mocked = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('getGroupAggregations()', () => { @@ -74,7 +70,9 @@ describe('getGroupAggregations()', () => { const alertsClient = new AlertsClient(alertsClientParams); alertsClient.find = jest.fn().mockResolvedValue({ aggregations: {} }); - const featureIds = [AlertConsumers.STACK_ALERTS]; + const ruleTypeIds = ['.es-query']; + const consumers = ['stackAlerts']; + const groupByField = 'kibana.alert.rule.name'; const aggregations = { usersCount: { @@ -86,7 +84,8 @@ describe('getGroupAggregations()', () => { const filters = [{ range: { '@timestamp': { gte: 'now-1d/d', lte: 'now/d' } } }]; await alertsClient.getGroupAggregations({ - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -95,7 +94,8 @@ describe('getGroupAggregations()', () => { }); expect(alertsClient.find).toHaveBeenCalledWith({ - featureIds, + ruleTypeIds, + consumers, aggs: { groupByFields: { terms: { @@ -157,7 +157,7 @@ describe('getGroupAggregations()', () => { }); const result = await alertsClient.getGroupAggregations({ - featureIds: [AlertConsumers.STACK_ALERTS], + ruleTypeIds: ['.es-query'], groupByField: 'kibana.alert.rule.name', aggregations: {}, filters: [], @@ -176,7 +176,7 @@ describe('getGroupAggregations()', () => { await expect(() => alertsClient.getGroupAggregations({ - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], groupByField: 'kibana.alert.rule.name', pageIndex: 101, pageSize: 50, @@ -186,7 +186,7 @@ describe('getGroupAggregations()', () => { ); await expect(() => alertsClient.getGroupAggregations({ - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], groupByField: 'kibana.alert.rule.name', pageIndex: 10, pageSize: 5000, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts new file mode 100644 index 0000000000000..deb3b82058843 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts @@ -0,0 +1,311 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AlertsClient, ConstructorOptions } from '../alerts_client'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { JsonObject } from '@kbn/utility-types'; + +jest.mock('uuid', () => ({ v4: () => 'unique-value' })); + +const alertingAuthMock = alertingAuthorizationMock.create(); +const esClientMock = elasticsearchClientMock.createElasticsearchClient(); +const auditLogger = auditLoggerMock.create(); + +const alertsClientParams: jest.Mocked = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn().mockReturnValue(['stack-index']), +}; + +const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + '.es-query', + { + producer: 'stackAlerts', + id: '.es-query', + alerts: { + context: 'stack', + }, + authorizedConsumers: {}, + }, + ], +]); + +const filter = { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + filter: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.rule_type_id': '.es-query' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'stackAlerts' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'alerts' } }], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, + }, + }, + { term: { 'kibana.space_ids': 'default' } }, + { terms: { 'kibana.alert.rule.rule_type_id': ['.es-query'] } }, + ], + }, +}; + +describe('getAlertSummary()', () => { + beforeEach(() => { + jest.clearAllMocks(); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAllAuthorizedRuleTypesFindOperation.mockResolvedValue(authorizedRuleTypes); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: filter as unknown as JsonObject, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + }); + + test('calls find() with the correct params', async () => { + const alertsClient = new AlertsClient(alertsClientParams) as jest.Mocked; + alertsClient.find = jest.fn().mockResolvedValue({ aggregations: {} }); + + const ruleTypeIds = ['.es-query']; + const consumers = ['stackAlerts']; + + await alertsClient.getAlertSummary({ + gte: 'now-1d/d', + lte: 'now/d', + ruleTypeIds, + consumers, + }); + + expect(esClientMock.search.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "body": Object { + "_source": undefined, + "aggs": Object { + "active_alerts_bucket": Object { + "date_histogram": Object { + "extended_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "field": "kibana.alert.time_range", + "fixed_interval": "1m", + "hard_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "min_doc_count": 0, + }, + }, + "count": Object { + "terms": Object { + "field": "kibana.alert.status", + }, + }, + "recovered_alerts": Object { + "aggs": Object { + "container": Object { + "date_histogram": Object { + "extended_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "field": "kibana.alert.end", + "fixed_interval": "1m", + "min_doc_count": 0, + }, + }, + }, + "filter": Object { + "term": Object { + "kibana.alert.status": "recovered", + }, + }, + }, + }, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "test_default_space_id", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "stackAlerts", + ], + }, + }, + ], + "must": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "kibana.alert.time_range": Object { + "gt": "now-1d/d", + "lt": "now/d", + }, + }, + }, + ], + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": 0, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": "stack-index", + "seq_no_primary_term": true, + }, + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts index bd6a1b2695cd1..4b9587b8e0ca1 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts @@ -16,7 +16,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -35,41 +34,38 @@ const alertsClientParams: jest.Mocked = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('update()', () => { diff --git a/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts b/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts index e1524b99f88d9..58ea503aa6ed4 100644 --- a/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts +++ b/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts @@ -19,17 +19,15 @@ import { export async function getAuthzFilter( authorization: PublicMethodsOf, - operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find, - featuresIds?: Set + operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find ) { - const { filter } = await authorization.getAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + const { filter } = await authorization.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { consumer: ALERT_RULE_CONSUMER, ruleTypeId: ALERT_RULE_TYPE_ID }, }, operation, - featuresIds - ); + }); return filter; } diff --git a/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx new file mode 100644 index 0000000000000..600177e1c33ea --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getConsumersFilter } from './get_consumers_filter'; + +describe('getConsumersFilter()', () => { + it('should return a consumers filter', () => { + expect(getConsumersFilter(['foo', 'bar'])).toStrictEqual({ + terms: { + 'kibana.alert.rule.consumer': ['foo', 'bar'], + }, + }); + }); + + it('should return undefined if no consumers are provided', () => { + expect(getConsumersFilter()).toBeUndefined(); + }); + + it('should return undefined if an empty array is provided', () => { + expect(getConsumersFilter([])).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx new file mode 100644 index 0000000000000..c5089416b7ef5 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ALERT_RULE_CONSUMER } from '../../common/technical_rule_data_field_names'; + +export function getConsumersFilter(consumers?: string[]) { + return consumers && consumers.length > 0 + ? { terms: { [ALERT_RULE_CONSUMER]: consumers } } + : undefined; +} diff --git a/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx new file mode 100644 index 0000000000000..7254f25256c2f --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getRuleTypeIdsFilter } from './get_rule_type_ids_filter'; + +describe('getRuleTypeIdsFilter()', () => { + it('should return a rule type ids filter', () => { + expect(getRuleTypeIdsFilter(['foo', 'bar'])).toStrictEqual({ + terms: { + 'kibana.alert.rule.rule_type_id': ['foo', 'bar'], + }, + }); + }); + + it('should return undefined if no rule type ids are provided', () => { + expect(getRuleTypeIdsFilter()).toBeUndefined(); + }); + + it('should return undefined if an empty array is provided', () => { + expect(getRuleTypeIdsFilter([])).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx new file mode 100644 index 0000000000000..f204d6d17acff --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ALERT_RULE_TYPE_ID } from '../../common/technical_rule_data_field_names'; + +export function getRuleTypeIdsFilter(ruleTypeIds?: string[]) { + return ruleTypeIds && ruleTypeIds.length > 0 + ? { terms: { [ALERT_RULE_TYPE_ID]: ruleTypeIds } } + : undefined; +} diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 60ee2256ae377..ae1159843b170 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -18,10 +18,7 @@ import { ServiceStatusLevels, } from '@kbn/core/server'; -import type { - PluginSetupContract as AlertingSetup, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { SecurityPluginSetup } from '@kbn/security-plugin/server'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import type { @@ -40,11 +37,11 @@ import { ruleRegistrySearchStrategyProvider, RULE_SEARCH_STRATEGY_NAME } from '. export interface RuleRegistryPluginSetupDependencies { security?: SecurityPluginSetup; data: DataPluginSetup; - alerting: AlertingSetup; + alerting: AlertingServerSetup; } export interface RuleRegistryPluginStartDependencies { - alerting: AlertingStart; + alerting: AlertingServerStart; data: DataPluginStart; spaces?: SpacesPluginStart; } @@ -56,7 +53,7 @@ export interface RuleRegistryPluginSetupContract { export interface RuleRegistryPluginStartContract { getRacClientWithRequest: (req: KibanaRequest) => Promise; - alerting: AlertingStart; + alerting: AlertingServerStart; } export class RuleRegistryPlugin @@ -165,7 +162,7 @@ export class RuleRegistryPlugin logger, esClient: core.elasticsearch.client.asInternalUser, // NOTE: Alerts share the authorization client with the alerting plugin - getAlertingAuthorization(request: KibanaRequest) { + async getAlertingAuthorization(request: KibanaRequest) { return plugins.alerting.getAlertingAuthorizationWithRequest(request); }, securityPluginSetup: security, @@ -175,7 +172,7 @@ export class RuleRegistryPlugin getAlertIndicesAlias: plugins.alerting.getAlertIndicesAlias, }); - const getRacClientWithRequest = (request: KibanaRequest) => { + const getRacClientWithRequest = async (request: KibanaRequest) => { return alertsClientFactory.create(request); }; @@ -190,7 +187,7 @@ export class RuleRegistryPlugin return function alertsRouteHandlerContext(context, request): RacApiRequestHandlerContext { return { getAlertsClient: async () => { - const createdClient = alertsClientFactory.create(request); + const createdClient = await alertsClientFactory.create(request); return createdClient; }, }; diff --git a/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts b/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts index d3857c4c49f17..7f214c95b0fcc 100644 --- a/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts @@ -12,7 +12,7 @@ export const getReadIndexRequest = () => requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/index`, - query: { features: 'siem' }, + query: { ruleTypeIds: 'siem.esqlRule' }, }); export const getReadRequest = () => @@ -33,18 +33,18 @@ export const getUpdateRequest = () => }, }); -export const getReadFeatureIdsRequest = () => +export const getFindRequest = () => requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { registrationContext: ['security'] }, + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/find`, + body: { rule_type_ids: ['siem.esqlRule'], consumers: ['siem'] }, }); export const getO11yBrowserFields = () => requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/browser_fields`, - query: { featureIds: ['apm', 'logs'] }, + query: { ruleTypeIds: ['apm.anomaly', 'logs.alert.document.count'] }, }); export const getMetricThresholdAADFields = () => @@ -59,7 +59,14 @@ export const getAlertsGroupAggregationsRequest = () => method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + consumers: ['apm'], groupByField: 'kibana.alert.rule.name', aggregations: { unitsCount: { diff --git a/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts b/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts index 6afba9e232c5e..1fef218202f2d 100644 --- a/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts +++ b/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts @@ -39,6 +39,8 @@ const buildResponses = (method: Method, calls: MockCall[]): ResponseCall[] => { status: call.statusCode, body: call.body, })); + case 'notFound': + return calls.map(([call]) => ({ status: 404, body: call.body })); default: throw new Error(`Encountered unexpected call to response.${method}`); } diff --git a/x-pack/plugins/rule_registry/server/routes/find.test.ts b/x-pack/plugins/rule_registry/server/routes/find.test.ts new file mode 100644 index 0000000000000..c84868c39f889 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/routes/find.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 { findAlertsByQueryRoute } from './find'; +import { requestContextMock } from './__mocks__/request_context'; +import { getFindRequest } from './__mocks__/request_responses'; +import { serverMock } from './__mocks__/server'; + +describe('findAlertsByQueryRoute', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + + beforeEach(async () => { + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + // @ts-expect-error: More properties are not needed + clients.rac.find.mockResolvedValue({ hits: { hits: [] } }); + + findAlertsByQueryRoute(server.router); + }); + + test('returns 200 when querying for alerts', async () => { + const response = await server.inject(getFindRequest(), context); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ hits: { hits: [] } }); + }); + + test('calls the alerts client correctly', async () => { + const response = await server.inject(getFindRequest(), context); + + expect(response.status).toEqual(200); + expect(clients.rac.find).toHaveBeenCalledWith({ + _source: undefined, + aggs: undefined, + consumers: ['siem'], + index: undefined, + query: undefined, + ruleTypeIds: ['siem.esqlRule'], + search_after: undefined, + size: undefined, + sort: undefined, + track_total_hits: undefined, + }); + }); + + test('accepts not defined ryleTypeIds and consumers', async () => { + const response = await server.inject({ ...getFindRequest(), body: {} }, context); + expect(response.status).toEqual(200); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/routes/find.ts b/x-pack/plugins/rule_registry/server/routes/find.ts index 4ce4567dd35bd..d41de4d64f71f 100644 --- a/x-pack/plugins/rule_registry/server/routes/find.ts +++ b/x-pack/plugins/rule_registry/server/routes/find.ts @@ -25,7 +25,8 @@ export const findAlertsByQueryRoute = (router: IRouter t.exact( t.partial({ aggs: t.record(t.string, t.intersection([metricsAggsSchemas, bucketAggsSchemas])), - feature_ids: t.union([t.array(t.string), t.undefined]), + rule_type_ids: t.union([t.array(t.string), t.undefined]), + consumers: t.union([t.array(t.string), t.undefined]), index: t.string, query: t.object, search_after: t.union([t.array(t.number), t.array(t.string), t.undefined]), @@ -50,7 +51,8 @@ export const findAlertsByQueryRoute = (router: IRouter try { const { aggs, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, index, query, // eslint-disable-next-line @typescript-eslint/naming-convention @@ -65,7 +67,8 @@ export const findAlertsByQueryRoute = (router: IRouter const alertsClient = await racContext.getAlertsClient(); const alerts = await alertsClient.find({ aggs, - featureIds, + ruleTypeIds, + consumers, index, query, search_after, diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts index b8ef01847d8ea..28d901dc5a137 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts @@ -31,6 +31,28 @@ describe('getAlertsIndexRoute', () => { expect(response.body).toEqual({ index_name: ['alerts-security.alerts'] }); }); + test('accepts an array of string ', async () => { + const ruleTypeIds = ['foo', 'bar']; + + await server.inject({ ...getReadIndexRequest(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(ruleTypeIds); + }); + + test('accepts a single string', async () => { + const ruleTypeIds = 'foo'; + + await server.inject({ ...getReadIndexRequest(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ruleTypeIds]); + }); + + test('accepts not defined ryleTypeIds', async () => { + await server.inject({ ...getReadIndexRequest(), query: {} }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(undefined); + }); + describe('request validation', () => { test('rejects invalid query params', async () => { await expect( @@ -38,12 +60,12 @@ describe('getAlertsIndexRoute', () => { requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/index`, - query: { features: 4 }, + query: { ruleTypeIds: 4 }, }), context ) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"features\\"'"` + `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"ruleTypeIds\\"'"` ); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts index aa3ec89fde7c8..e83d784bd4fb7 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts @@ -8,7 +8,6 @@ import { IRouter } from '@kbn/core/server'; import * as t from 'io-ts'; import { transformError } from '@kbn/securitysolution-es-utils'; -import { validFeatureIds } from '@kbn/rule-data-utils'; import { buildRouteValidation } from './utils/route_validation'; import { RacRequestHandlerContext } from '../types'; @@ -22,7 +21,7 @@ export const getAlertsIndexRoute = (router: IRouter) = query: buildRouteValidation( t.exact( t.partial({ - features: t.string, + ruleTypeIds: t.union([t.string, t.array(t.string)]), }) ) ), @@ -40,10 +39,17 @@ export const getAlertsIndexRoute = (router: IRouter) = try { const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); - const { features } = request.query; - const indexName = await alertsClient.getAuthorizedAlertsIndices( - features?.split(',') ?? validFeatureIds - ); + const { ruleTypeIds } = request.query; + + const ruleTypeIdsAsArray = + ruleTypeIds != null + ? Array.isArray(ruleTypeIds) + ? ruleTypeIds + : [ruleTypeIds] + : ruleTypeIds; + + const indexName = await alertsClient.getAuthorizedAlertsIndices(ruleTypeIdsAsArray); + return response.ok({ body: { index_name: indexName }, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts index e15f2d40dc826..961b33310bfc7 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts @@ -35,7 +35,7 @@ describe('getAlertSummaryRoute', () => { requestMock.create({ method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, - body: { gte: 4, lte: 3, featureIds: ['logs'] }, + body: { gte: 4, lte: 3, ruleTypeIds: ['logs'] }, }), context ) @@ -52,7 +52,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16', - featureIds: ['logs'], + ruleTypeIds: ['logs'], }, }), context @@ -76,7 +76,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16T16:00:00.000Z', - featureIds: ['logs'], + ruleTypeIds: ['logs'], fixed_interval: 'xx', }, }), @@ -102,7 +102,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16T16:00:00.000Z', - featureIds: ['logs'], + ruleTypeIds: ['logs'], boop: 'unknown', }, }), @@ -112,5 +112,68 @@ describe('getAlertSummaryRoute', () => { `"Request was rejected with message: 'invalid keys \\"boop\\"'"` ); }); + + test('rejects without ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('accepts consumers', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + consumers: ['foo'], + ruleTypeIds: ['bar'], + }, + }), + context + ) + ).resolves.not.toThrow(); + }); + + test('calls the alerts client correctly', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + consumers: ['foo'], + ruleTypeIds: ['bar'], + }, + }), + context + ) + ).resolves.not.toThrow(); + + expect(clients.rac.getAlertSummary).toHaveBeenCalledWith({ + consumers: ['foo'], + filter: undefined, + fixedInterval: undefined, + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + ruleTypeIds: ['bar'], + }); + }); }); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts index e33b0137a932e..9be3de57fdc0a 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts @@ -27,13 +27,14 @@ export const getAlertSummaryRoute = (router: IRouter) t.type({ gte: t.string, lte: t.string, - featureIds: t.array(t.string), + ruleTypeIds: t.array(t.string), }) ), t.exact( t.partial({ fixed_interval: t.string, filter: t.array(t.object), + consumers: t.array(t.string), }) ), ]) @@ -52,7 +53,14 @@ export const getAlertSummaryRoute = (router: IRouter) try { const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); - const { gte, lte, featureIds, filter, fixed_interval: fixedInterval } = request.body; + const { + gte, + lte, + ruleTypeIds, + consumers, + filter, + fixed_interval: fixedInterval, + } = request.body; if ( !( moment(gte, 'YYYY-MM-DDTHH:mm:ss.SSSZ', true).isValid() && @@ -71,7 +79,8 @@ export const getAlertSummaryRoute = (router: IRouter) const aggs = await alertsClient.getAlertSummary({ gte, lte, - featureIds, + ruleTypeIds, + consumers, filter: filter as estypes.QueryDslQueryContainer[], fixedInterval, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts index 1ce32adc37e62..5bf3a4a1622cd 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts @@ -200,7 +200,7 @@ describe('getAlertsGroupAggregations', () => { context ) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"featureIds\\"'"` + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` ); }); @@ -211,7 +211,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', aggregations: { scriptedAggregation: { @@ -231,7 +237,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', filters: [ { @@ -256,7 +268,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', aggregations: {}, runtimeMappings: {}, @@ -280,4 +298,84 @@ describe('getAlertsGroupAggregations', () => { message: 'Unable to get alerts', }); }); + + test('rejects without ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + groupByField: 'kibana.alert.rule.name', + }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('accepts consumers', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + groupByField: 'kibana.alert.rule.name', + consumers: ['foo'], + }, + }), + context + ) + ).resolves.not.toThrow(); + }); + + test('calls the alerts client correctly', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + groupByField: 'kibana.alert.rule.name', + consumers: ['foo'], + }, + }), + context + ) + ).resolves.not.toThrow(); + + expect(clients.rac.getGroupAggregations).toHaveBeenCalledWith({ + aggregations: undefined, + consumers: ['foo'], + filters: undefined, + groupByField: 'kibana.alert.rule.name', + pageIndex: 0, + pageSize: 10, + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + sort: undefined, + }); + }); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts index 34c56b7691a1f..6924025f2b33a 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts @@ -22,17 +22,24 @@ export const getAlertsGroupAggregations = (router: IRouter { const { - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -58,7 +66,8 @@ export const getAlertsGroupAggregations = (router: IRouter { - let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); - const path = `${BASE_RAC_ALERTS_API_PATH}/browser_fields`; - - beforeEach(async () => { - server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - }); - - describe('when racClient returns o11y indices', () => { - beforeEach(() => { - clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([ - '.alerts-observability.logs.alerts-default', - ]); - - getBrowserFieldsByFeatureId(server.router); - }); - - test('route registered', async () => { - const response = await server.inject(getO11yBrowserFields(), context); - - expect(response.status).toEqual(200); - }); - - test('rejects invalid featureId type', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path, - query: { featureIds: undefined }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"featureIds\\"'"` - ); - }); - - test('returns error status if rac client "getAuthorizedAlertsIndices" fails', async () => { - clients.rac.getAuthorizedAlertsIndices.mockRejectedValue(new Error('Unable to get index')); - const response = await server.inject(getO11yBrowserFields(), context); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ - attributes: { success: false }, - message: 'Unable to get index', - }); - }); - }); -}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts new file mode 100644 index 0000000000000..819ed89bc7c08 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; +import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_rule_type_ids'; +import { requestContextMock } from './__mocks__/request_context'; +import { getO11yBrowserFields } from './__mocks__/request_responses'; +import { requestMock, serverMock } from './__mocks__/server'; + +describe('getBrowserFieldsByFeatureId', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + const path = `${BASE_RAC_ALERTS_API_PATH}/browser_fields`; + + beforeEach(async () => { + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([ + '.alerts-observability.logs.alerts-default', + ]); + + clients.rac.getBrowserFields.mockResolvedValue({ browserFields: {}, fields: [] }); + + getBrowserFieldsByFeatureId(server.router); + }); + + test('route registered', async () => { + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(200); + }); + + test('it calls getAuthorizedAlertsIndices with o11y rule types', async () => { + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ + 'apm.anomaly', + 'logs.alert.document.count', + ]); + }); + + test('it calls getAuthorizedAlertsIndices only for o11y rule types when siem rule types are mixed', async () => { + const response = await server.inject( + { + ...getO11yBrowserFields(), + query: { ruleTypeIds: ['apm.anomaly', 'siem.esqlRuleType'] }, + }, + context + ); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(['apm.anomaly']); + }); + + test('it does not call getAuthorizedAlertsIndices with siem rule types', async () => { + const response = await server.inject( + { + ...getO11yBrowserFields(), + query: { ruleTypeIds: ['siem.esqlRuleType'] }, + }, + context + ); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).not.toHaveBeenCalledWith(); + }); + + test('accepts an array of string ', async () => { + const ruleTypeIds = ['foo', 'bar']; + + await server.inject({ ...getO11yBrowserFields(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(ruleTypeIds); + }); + + test('accepts a single string', async () => { + const ruleTypeIds = 'foo'; + + await server.inject({ ...getO11yBrowserFields(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ruleTypeIds]); + }); + + test('returns 404 when getAuthorizedAlertsIndices returns an empty array', async () => { + clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([]); + + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(404); + }); + + test('rejects invalid ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'get', + path, + query: { ruleTypeIds: undefined }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('returns error status if rac client "getAuthorizedAlertsIndices" fails', async () => { + clients.rac.getAuthorizedAlertsIndices.mockRejectedValue(new Error('Unable to get index')); + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ + attributes: { success: false }, + message: 'Unable to get index', + }); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts similarity index 83% rename from x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts rename to x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts index 20a3781be6973..4c27095ae77c6 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts @@ -9,6 +9,7 @@ import { IRouter } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import * as t from 'io-ts'; +import { isSiemRuleType } from '@kbn/rule-data-utils'; import { RacRequestHandlerContext } from '../types'; import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; import { buildRouteValidation } from './utils/route_validation'; @@ -21,7 +22,7 @@ export const getBrowserFieldsByFeatureId = (router: IRouter fId !== 'siem' - ); + const { ruleTypeIds = [] } = request.query; + + const onlyO11yRuleTypeIds = ( + Array.isArray(ruleTypeIds) ? ruleTypeIds : [ruleTypeIds] + ).filter((ruleTypeId) => !isSiemRuleType(ruleTypeId)); + const o11yIndices = - (onlyO11yFeatureIds - ? await alertsClient.getAuthorizedAlertsIndices(onlyO11yFeatureIds) + (onlyO11yRuleTypeIds + ? await alertsClient.getAuthorizedAlertsIndices(onlyO11yRuleTypeIds) : []) ?? []; + if (o11yIndices.length === 0) { return response.notFound({ body: { - message: `No alerts-observability indices found for featureIds [${featureIds}]`, + message: `No alerts-observability indices found for rule type ids [${onlyO11yRuleTypeIds}]`, attributes: { success: false }, }, }); @@ -58,10 +62,11 @@ export const getBrowserFieldsByFeatureId = (router: IRouter { - let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); - - beforeEach(async () => { - server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - - clients.rac.getFeatureIdsByRegistrationContexts.mockResolvedValue(['siem']); - - getFeatureIdsByRegistrationContexts(server.router); - }); - - test('returns 200 when querying for features ids', async () => { - const response = await server.inject(getReadFeatureIdsRequest(), context); - - expect(response.status).toEqual(200); - expect(response.body).toEqual(['siem']); - }); - - describe('request validation', () => { - test('rejects invalid query params', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { registrationContext: 4 }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"registrationContext\\"'"` - ); - }); - - test('rejects unknown query params', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { boop: 'siem' }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'invalid keys \\"boop\\"'"` - ); - }); - }); - - test('returns error status if rac client "getFeatureIdsByRegistrationContexts" fails', async () => { - clients.rac.getFeatureIdsByRegistrationContexts.mockRejectedValue( - new Error('Unable to get feature ids') - ); - const response = await server.inject(getReadFeatureIdsRequest(), context); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ - attributes: { success: false }, - message: 'Unable to get feature ids', - }); - }); -}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts b/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts deleted file mode 100644 index 43bd491daafbe..0000000000000 --- a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts +++ /dev/null @@ -1,71 +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 { IRouter } from '@kbn/core/server'; -import * as t from 'io-ts'; -import { transformError } from '@kbn/securitysolution-es-utils'; - -import { RacRequestHandlerContext } from '../types'; -import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; -import { buildRouteValidation } from './utils/route_validation'; - -export const getFeatureIdsByRegistrationContexts = (router: IRouter) => { - router.get( - { - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - validate: { - query: buildRouteValidation( - t.exact( - t.partial({ - registrationContext: t.union([t.string, t.array(t.string)]), - }) - ) - ), - }, - security: { - authz: { - requiredPrivileges: ['rac'], - }, - }, - options: { - access: 'internal', - }, - }, - async (context, request, response) => { - try { - const racContext = await context.rac; - const alertsClient = await racContext.getAlertsClient(); - const { registrationContext = [] } = request.query; - const featureIds = await alertsClient.getFeatureIdsByRegistrationContexts( - Array.isArray(registrationContext) ? registrationContext : [registrationContext] - ); - return response.ok({ - body: featureIds, - }); - } catch (exc) { - const err = transformError(exc); - const contentType = { - 'content-type': 'application/json', - }; - const defaultedHeaders = { - ...contentType, - }; - - return response.customError({ - headers: defaultedHeaders, - statusCode: err.statusCode, - body: { - message: err.message, - attributes: { - success: false, - }, - }, - }); - } - } - ); -}; diff --git a/x-pack/plugins/rule_registry/server/routes/index.ts b/x-pack/plugins/rule_registry/server/routes/index.ts index ae9f113ee0ac1..72ecfc4c9b8ef 100644 --- a/x-pack/plugins/rule_registry/server/routes/index.ts +++ b/x-pack/plugins/rule_registry/server/routes/index.ts @@ -13,8 +13,7 @@ import { updateAlertByIdRoute } from './update_alert_by_id'; import { getAlertsIndexRoute } from './get_alert_index'; import { bulkUpdateAlertsRoute } from './bulk_update_alerts'; import { findAlertsByQueryRoute } from './find'; -import { getFeatureIdsByRegistrationContexts } from './get_feature_ids_by_registration_contexts'; -import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_feature_id'; +import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_rule_type_ids'; import { getAlertSummaryRoute } from './get_alert_summary'; import { getAADFieldsByRuleType } from './get_aad_fields_by_rule_type'; @@ -25,7 +24,6 @@ export function defineRoutes(router: IRouter) { bulkUpdateAlertsRoute(router); findAlertsByQueryRoute(router); getAlertsGroupAggregations(router); - getFeatureIdsByRegistrationContexts(router); getBrowserFieldsByFeatureId(router); getAlertSummaryRoute(router); getAADFieldsByRuleType(router); diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts index 9b279a541b3e9..cfbfafd0092bf 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts @@ -17,7 +17,6 @@ export const ruleDataServiceMock = { initializeIndex: jest.fn(), findIndexByName: jest.fn(), findIndexByFeature: jest.fn(), - findFeatureIdsByRegistrationContexts: jest.fn(), }), }; diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts index efe4a5dd4f32f..91192848830ec 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts @@ -78,12 +78,6 @@ export interface IRuleDataService { * Note: features are used in RBAC. */ findIndexByFeature(featureId: ValidFeatureId, dataset: Dataset): IndexInfo | null; - - /** - * Looks up Kibana "feature" associated with the given registration context. - * Note: features are used in RBAC. - */ - findFeatureIdsByRegistrationContexts(registrationContexts: string[]): string[]; } // TODO: This is a leftover. Remove its usage from the "observability" plugin and delete it. @@ -248,17 +242,6 @@ export class RuleDataService implements IRuleDataService { return this.indicesByBaseName.get(baseName) ?? null; } - public findFeatureIdsByRegistrationContexts(registrationContexts: string[]): string[] { - const featureIds: string[] = []; - registrationContexts.forEach((rc) => { - const featureId = this.registrationContextByFeatureId.get(rc); - if (featureId) { - featureIds.push(featureId); - } - }); - return featureIds; - } - public findIndexByFeature(featureId: ValidFeatureId, dataset: Dataset): IndexInfo | null { const foundIndices = this.indicesByFeatureId.get(featureId) ?? []; if (dataset && foundIndices.length > 0) { diff --git a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts index 4dabfb3feb390..1086714ab758a 100644 --- a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts +++ b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts @@ -4,12 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { of } from 'rxjs'; +import { lastValueFrom, of } from 'rxjs'; import { merge } from 'lodash'; import { loggerMock } from '@kbn/logging-mocks'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { ALERT_EVENTS_FIELDS } from '@kbn/alerts-as-data-utils'; -import { ruleRegistrySearchStrategyProvider, EMPTY_RESPONSE } from './search_strategy'; +import { ruleRegistrySearchStrategyProvider } from './search_strategy'; import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; import { SearchStrategyDependencies } from '@kbn/data-plugin/server'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; @@ -18,6 +17,9 @@ import { spacesMock } from '@kbn/spaces-plugin/server/mocks'; import type { RuleRegistrySearchRequest } from '../../common'; import * as getAuthzFilterImport from '../lib/get_authz_filter'; import { getIsKibanaRequest } from '../lib/get_is_kibana_request'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { Boom } from '@hapi/boom'; +import { KbnSearchError } from '@kbn/data-plugin/server/search/report_search_error'; jest.mock('../lib/get_is_kibana_request'); @@ -53,8 +55,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const security = securityMock.createSetup(); const spaces = spacesMock.createStart(); const logger = loggerMock.create(); + const authorizationMock = alertingAuthorizationMock.create(); const getAuthorizedRuleTypesMock = jest.fn(); const getAlertIndicesAliasMock = jest.fn(); + const response = getBasicResponse({ rawResponse: { hits: { @@ -73,13 +77,19 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const searchStrategySearch = jest.fn().mockImplementation(() => of(response)); beforeEach(() => { + jest.clearAllMocks(); + getAuthorizedRuleTypesMock.mockResolvedValue([]); getAlertIndicesAliasMock.mockReturnValue(['test']); - const authorizationMock = { - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, - } as never; alerting.getAlertingAuthorizationWithRequest.mockResolvedValue(authorizationMock); alerting.getAlertIndicesAlias = getAlertIndicesAliasMock; + alerting.listTypes.mockReturnValue( + // @ts-expect-error: rule type properties are not needed for the test + new Map([ + ['.es-query', {}], + ['siem.esqlRule', {}], + ]) + ); data.search.getSearchStrategy.mockImplementation(() => { return { @@ -115,7 +125,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { getAuthorizedRuleTypesMock.mockResolvedValue([]); getAlertIndicesAliasMock.mockReturnValue(['observability-logs']); const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -124,16 +134,16 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - const result = await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + const result = await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); expect(result).toEqual(response); }); it('should return an empty response if no valid indices are found', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -145,15 +155,30 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - const result = await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); - expect(result).toBe(EMPTY_RESPONSE); + const result = await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + expect(result).toMatchInlineSnapshot(` + Object { + "inspect": Object { + "dsl": Array [ + "{}", + ], + }, + "rawResponse": Object { + "hits": Object { + "hits": Array [], + "total": 0, + }, + }, + } + `); }); - it('should not apply rbac filters for siem', async () => { + it('should not apply rbac filters for siem rule types', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], }; const options = {}; const deps = { @@ -165,15 +190,16 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(getAuthzFilterSpy).not.toHaveBeenCalled(); }); - it('should throw an error if requesting multiple featureIds and one is SIEM', async () => { + it('should throw an error if requesting multiple rule types and one is for siem', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM, AlertConsumers.LOGS], + ruleTypeIds: ['.es-query', 'siem.esqlRule'], }; const options = {}; const deps = { @@ -186,19 +212,70 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); let err; + try { - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); } catch (e) { err = e; } - expect(err).toBeDefined(); + + expect(err.statusCode).toBe(400); + expect(err.message).toBe( + 'The privateRuleRegistryAlertsSearchStrategy search strategy is unable to accommodate requests containing multiple rule types with mixed authorization.' + ); + }); + + it('should not throw an error with empty rule type ids', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: [], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue([]); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await expect( + lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ) + ).resolves.not.toThrow(); + }); + + it('should filter out invalid rule types', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query', 'not-exist'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await expect( + lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ) + ).resolves.not.toThrow(); + + expect(authorizationMock.getAllAuthorizedRuleTypesFindOperation).toHaveBeenCalledWith({ + authorizationEntity: 'alert', + ruleTypeIds: ['.es-query'], + }); }); it('should use internal user when requesting o11y alerts as RBAC is applied', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -209,16 +286,17 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(data.search.searchAsInternalUser.search).toHaveBeenCalled(); expect(searchStrategySearch).not.toHaveBeenCalled(); }); it('should use scoped user when requesting siem alerts as RBAC is not applied', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], }; const options = {}; const deps = { @@ -230,16 +308,17 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(data.search.searchAsInternalUser.search as jest.Mock).not.toHaveBeenCalled(); expect(searchStrategySearch).toHaveBeenCalled(); }); it('should support pagination', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], pagination: { pageSize: 10, pageIndex: 0, @@ -254,9 +333,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect((data.search.searchAsInternalUser.search as jest.Mock).mock.calls.length).toBe(1); expect( (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0].params.body.size @@ -268,7 +348,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { it('should support sorting', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], sort: [ { test: { @@ -286,9 +366,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect((data.search.searchAsInternalUser.search as jest.Mock).mock.calls.length).toBe(1); expect( (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0].params.body.sort @@ -297,7 +378,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { it('passes the query ids if provided', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], query: { ids: { values: ['test-id'] }, }, @@ -311,21 +392,24 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + const arg0 = searchStrategySearch.mock.calls[0][0]; expect(arg0.params.body.fields.length).toEqual( // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and // fields.push({ field: 'signal.*', include_unmapped: false }); ALERT_EVENTS_FIELDS.length + 2 ); + expect.arrayContaining([ expect.objectContaining({ x: 2, y: 3, }), ]); + expect(arg0).toEqual( expect.objectContaining({ id: undefined, @@ -355,9 +439,9 @@ describe('ruleRegistrySearchStrategyProvider()', () => { ); }); - it('passes the fields if provided', async () => { + it('passes the fields if provided for siem rule types', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], query: { ids: { values: ['test-id'] }, }, @@ -372,42 +456,264 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); const arg0 = searchStrategySearch.mock.calls[0][0]; - expect(arg0.params.body.fields.length).toEqual( + const fields = arg0.params.body.fields; + + expect(fields.length).toEqual( // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and // fields.push({ field: 'signal.*', include_unmapped: false }); + my-super-field ALERT_EVENTS_FIELDS.length + 3 ); - expect(arg0).toEqual( - expect.objectContaining({ - id: undefined, - params: expect.objectContaining({ - allow_no_indices: true, - body: expect.objectContaining({ - _source: false, - fields: expect.arrayContaining([ - expect.objectContaining({ - field: 'my-super-field', - include_unmapped: true, - }), - ]), - from: 0, - query: { - ids: { - values: ['test-id'], + + const siemField = fields.find((field: { field: string }) => field.field === 'signal.*'); + const kibanaField = fields.find((field: { field: string }) => field.field === 'kibana.alert.*'); + const myField = fields.find((field: { field: string }) => field.field === 'my-super-field'); + + expect(siemField).toMatchInlineSnapshot(` + Object { + "field": "signal.*", + "include_unmapped": false, + } + `); + + expect(kibanaField).toMatchInlineSnapshot(` + Object { + "field": "kibana.alert.*", + "include_unmapped": false, + } + `); + + expect(myField).toMatchInlineSnapshot(` + Object { + "field": "my-super-field", + "include_unmapped": true, + } + `); + }); + + it('passes the fields if provided for o11y rule types', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + query: { + ids: { values: ['test-id'] }, + }, + fields: [{ field: 'my-super-field', include_unmapped: true }], + }; + const options = {}; + const deps = { + request: {}, + }; + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + const arg0 = (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0]; + const fields = arg0.params.body.fields; + + expect(fields.length).toEqual( + // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and + // fields.push({ field: '*', include_unmapped: false }); + my-super-field + 3 + ); + + const allField = fields.find((field: { field: string }) => field.field === '*'); + const kibanaField = fields.find((field: { field: string }) => field.field === 'kibana.alert.*'); + const myField = fields.find((field: { field: string }) => field.field === 'my-super-field'); + + expect(allField).toMatchInlineSnapshot(` + Object { + "field": "*", + "include_unmapped": true, + } + `); + + expect(kibanaField).toMatchInlineSnapshot(` + Object { + "field": "kibana.alert.*", + "include_unmapped": false, + } + `); + + expect(myField).toMatchInlineSnapshot(` + Object { + "field": "my-super-field", + "include_unmapped": true, + } + `); + }); + + it('should handle Boom errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new Boom('boom error message', { statusCode: 400 })); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(400); + expect(err.message).toBe('boom error message'); + }); + + it('should handle KbnSearchError errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new KbnSearchError('kbn search error message', 403)); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(403); + expect(err.message).toBe('kbn search error message'); + }); + + it('should convert errors to KbnSearchError errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new Error('plain error message')); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(500); + expect(err.message).toBe('plain error message'); + }); + + it('should apply the rule type IDs filter', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['siem.esqlRule'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + const arg0 = searchStrategySearch.mock.calls[0][0]; + expect(arg0.params.body.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + ], }, }, - size: 1000, - sort: [], - }), - ignore_unavailable: true, - index: ['security-siem'], - }), - }) + ], + }, + } + `); + }); + + it('should apply the consumers filter', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['siem.esqlRule'], + consumers: ['alerts'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) ); + + const arg0 = searchStrategySearch.mock.calls[0][0]; + expect(arg0.params.body.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "alerts", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + ], + }, + }, + ], + }, + } + `); }); }); diff --git a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts index a497008086c88..246b38aaf733d 100644 --- a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts +++ b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts @@ -4,28 +4,36 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { map, mergeMap, catchError } from 'rxjs'; + +import Boom from '@hapi/boom'; +import { map, mergeMap, catchError, of } from 'rxjs'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Logger } from '@kbn/core/server'; -import { from, of } from 'rxjs'; -import { isValidFeatureId, AlertConsumers } from '@kbn/rule-data-utils'; +import { from } from 'rxjs'; import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server'; import { ReadOperations, - PluginStartContract as AlertingStart, + AlertingServerStart, AlertingAuthorizationEntity, } from '@kbn/alerting-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { buildAlertFieldsRequest } from '@kbn/alerts-as-data-utils'; +import { partition } from 'lodash'; +import { isSiemRuleType } from '@kbn/rule-data-utils'; +import { KbnSearchError } from '@kbn/data-plugin/server/search/report_search_error'; import type { RuleRegistrySearchRequest, RuleRegistrySearchResponse } from '../../common'; import { MAX_ALERT_SEARCH_SIZE } from '../../common/constants'; import { AlertAuditAction, alertAuditEvent } from '..'; import { getSpacesFilter, getAuthzFilter } from '../lib'; +import { getRuleTypeIdsFilter } from '../lib/get_rule_type_ids_filter'; +import { getConsumersFilter } from '../lib/get_consumers_filter'; export const EMPTY_RESPONSE: RuleRegistrySearchResponse = { - rawResponse: {} as RuleRegistrySearchResponse['rawResponse'], + rawResponse: { + hits: { total: 0, hits: [] }, + } as unknown as RuleRegistrySearchResponse['rawResponse'], }; export const RULE_SEARCH_STRATEGY_NAME = 'privateRuleRegistryAlertsSearchStrategy'; @@ -35,7 +43,7 @@ const EXCLUDED_RULE_TYPE_IDS = ['siem.notifications']; export const ruleRegistrySearchStrategyProvider = ( data: PluginStart, - alerting: AlertingStart, + alerting: AlertingServerStart, logger: Logger, security?: SecurityPluginSetup, spaces?: SpacesPluginStart @@ -44,57 +52,69 @@ export const ruleRegistrySearchStrategyProvider = ( const requestUserEs = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY); return { search: (request, options, deps) => { + let params = {}; + // SIEM uses RBAC fields in their alerts but also utilizes ES DLS which // is different than every other solution so we need to special case // those requests. - let siemRequest = false; - let params = {}; - if (request.featureIds.length === 1 && request.featureIds[0] === AlertConsumers.SIEM) { - siemRequest = true; - } else if (request.featureIds.includes(AlertConsumers.SIEM)) { - throw new Error( - `The ${RULE_SEARCH_STRATEGY_NAME} search strategy is unable to accommodate requests containing multiple feature IDs and one of those IDs is SIEM.` + const isAnyRuleTypeESAuthorized = request.ruleTypeIds.some(isSiemRuleType); + const isEachRuleTypeESAuthorized = + // every returns true for empty arrays + request.ruleTypeIds.length > 0 && request.ruleTypeIds.every(isSiemRuleType); + + const registeredRuleTypes = alerting.listTypes(); + + const [validRuleTypeIds, invalidRuleTypeIds] = partition(request.ruleTypeIds, (ruleTypeId) => + registeredRuleTypes.has(ruleTypeId) + ); + + if (isAnyRuleTypeESAuthorized && !isEachRuleTypeESAuthorized) { + throw new KbnSearchError( + `The ${RULE_SEARCH_STRATEGY_NAME} search strategy is unable to accommodate requests containing multiple rule types with mixed authorization.`, + 400 ); } - request.featureIds.forEach((featureId) => { - if (!isValidFeatureId(featureId)) { - logger.warn( - `Found invalid feature '${featureId}' while using ${RULE_SEARCH_STRATEGY_NAME} search strategy. No alert data from this feature will be searched.` - ); - } + + invalidRuleTypeIds.forEach((ruleTypeId) => { + logger.warn( + `Found invalid rule type '${ruleTypeId}' while using ${RULE_SEARCH_STRATEGY_NAME} search strategy. No alert data from this rule type will be searched.` + ); }); const securityAuditLogger = security?.audit.asScoped(deps.request); const getActiveSpace = async () => spaces?.spacesService.getActiveSpace(deps.request); - const getAsync = async (featureIds: string[]) => { + + const getAsync = async (ruleTypeIds: string[]) => { const [space, authorization] = await Promise.all([ getActiveSpace(), alerting.getAlertingAuthorizationWithRequest(deps.request), ]); + let authzFilter; - const fIds = new Set(featureIds); - if (!siemRequest && featureIds.length > 0) { + + if (!isAnyRuleTypeESAuthorized && ruleTypeIds.length > 0) { authzFilter = (await getAuthzFilter( authorization, - ReadOperations.Find, - fIds + ReadOperations.Find )) as estypes.QueryDslQueryContainer; } - const authorizedRuleTypes = - featureIds.length > 0 - ? await authorization.getAuthorizedRuleTypes(AlertingAuthorizationEntity.Alert, fIds) - : []; + const authorizedRuleTypes = await authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); return { space, authzFilter, authorizedRuleTypes }; }; - return from(getAsync(request.featureIds)).pipe( + return from(getAsync(validRuleTypeIds)).pipe( mergeMap(({ space, authzFilter, authorizedRuleTypes }) => { - const allRuleTypes = authorizedRuleTypes.map((art: { id: string }) => art.id); - const ruleTypes = (allRuleTypes ?? []).filter( + const authorizedRuleTypesIds = Array.from(authorizedRuleTypes.keys()); + const ruleTypes = (authorizedRuleTypesIds ?? []).filter( (ruleTypeId: string) => !EXCLUDED_RULE_TYPE_IDS.includes(ruleTypeId) ); + const indices = alerting.getAlertIndicesAlias(ruleTypes, space?.id); + if (indices.length === 0) { return of(EMPTY_RESPONSE); } @@ -104,13 +124,26 @@ export const ruleRegistrySearchStrategyProvider = ( ? request.query?.bool?.filter : [request.query?.bool?.filter] : []; + if (authzFilter) { filter.push(authzFilter); } + if (space?.id) { filter.push(getSpacesFilter(space.id) as estypes.QueryDslQueryContainer); } + const ruleTypeFilter = getRuleTypeIdsFilter(request.ruleTypeIds); + const consumersFilter = getConsumersFilter(request.consumers); + + if (consumersFilter) { + filter.push(consumersFilter); + } + + if (ruleTypeFilter) { + filter.push(ruleTypeFilter); + } + const sort = request.sort ?? []; const query = { @@ -123,10 +156,11 @@ export const ruleRegistrySearchStrategyProvider = ( }, }), }; + let fields = request?.fields ?? []; fields.push({ field: 'kibana.alert.*', include_unmapped: false }); - if (siemRequest) { + if (isAnyRuleTypeESAuthorized) { fields.push({ field: 'signal.*', include_unmapped: false }); fields = fields.concat(buildAlertFieldsRequest([], false)); } else { @@ -149,7 +183,7 @@ export const ruleRegistrySearchStrategyProvider = ( ...(request.runtimeMappings ? { runtime_mappings: request.runtimeMappings } : {}), }, }; - return (siemRequest ? requestUserEs : internalUserEs).search( + return (isAnyRuleTypeESAuthorized ? requestUserEs : internalUserEs).search( { id: request.id, params }, options, deps @@ -180,7 +214,6 @@ export const ruleRegistrySearchStrategyProvider = ( return response; }), catchError((err) => { - // check if auth error, if yes, write to ecs logger if (securityAuditLogger != null && err?.output?.statusCode === 403) { securityAuditLogger.log( alertAuditEvent({ @@ -191,7 +224,15 @@ export const ruleRegistrySearchStrategyProvider = ( ); } - throw err; + if (Boom.isBoom(err)) { + throw new KbnSearchError(err.output.payload.message, err.output.statusCode); + } + + if (err instanceof KbnSearchError) { + throw err; + } + + throw new KbnSearchError(err.message, 500); }) ); }, diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts index afdc63712ba84..9900c889ae73e 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts @@ -570,7 +570,9 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper const bulkResponse = await ruleDataClientWriter.bulk({ body: [...duplicateAlertUpdates, ...mapAlertsToBulkCreate(augmentedAlerts)], - refresh: true, + // On serverless we can force a refresh to we don't wait for the longer refresh interval + // When too many refresh calls are done in a short period of time, they are throttled by stateless Elasticsearch + refresh: options.isServerless ? true : 'wait_for', }); if (bulkResponse == null) { diff --git a/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts b/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts index 357703c7b7521..ca7291e2fc2e5 100644 --- a/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts +++ b/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts @@ -99,4 +99,5 @@ export const createDefaultAlertExecutorOptions = < const date = new Date(Date.now()).toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }); diff --git a/x-pack/plugins/search_assistant/public/plugin.tsx b/x-pack/plugins/search_assistant/public/plugin.tsx index 15c1443045cdc..ef65f256d7b36 100644 --- a/x-pack/plugins/search_assistant/public/plugin.tsx +++ b/x-pack/plugins/search_assistant/public/plugin.tsx @@ -54,8 +54,9 @@ export class SearchAssistantPlugin pluginsStart, }); const isEnabled = appService.isEnabled(); + const aiAssistantIsEnabled = coreStart.application.capabilities.observabilityAIAssistant?.show; - if (!isEnabled) { + if (!isEnabled || !aiAssistantIsEnabled) { return {}; } diff --git a/x-pack/plugins/search_playground/kibana.jsonc b/x-pack/plugins/search_playground/kibana.jsonc index 37562347e9f37..3c4eaaddc81a2 100644 --- a/x-pack/plugins/search_playground/kibana.jsonc +++ b/x-pack/plugins/search_playground/kibana.jsonc @@ -18,6 +18,7 @@ "actions", "data", "encryptedSavedObjects", + "ml", "navigation", "share", "security", diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx index e78ed371468fc..ec0c12aa3bc16 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { mount } from 'enzyme'; import type { FC, PropsWithChildren } from 'react'; import React from 'react'; diff --git a/x-pack/plugins/security/public/components/use_badge.test.tsx b/x-pack/plugins/security/public/components/use_badge.test.tsx index 07d0261235301..643ebeffa8991 100644 --- a/x-pack/plugins/security/public/components/use_badge.test.tsx +++ b/x-pack/plugins/security/public/components/use_badge.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; diff --git a/x-pack/plugins/security/public/components/use_capabilities.test.tsx b/x-pack/plugins/security/public/components/use_capabilities.test.tsx index 5e8491199a5da..8a5a8eb3ebda8 100644 --- a/x-pack/plugins/security/public/components/use_capabilities.test.tsx +++ b/x-pack/plugins/security/public/components/use_capabilities.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts index 19378bfd8488b..72b9e44da3f43 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -26,6 +26,7 @@ describe('Security UsageCollector', () => { allowAccessAgreement = true, allowAuditLogging = true, allowRbac = true, + allowFips = true, isLicenseAvailable, }: Partial & { isLicenseAvailable: boolean }) => { const license = licenseMock.create(); @@ -34,6 +35,7 @@ describe('Security UsageCollector', () => { allowAccessAgreement, allowAuditLogging, allowRbac, + allowFips, } as SecurityLicenseFeatures); return license; }; @@ -44,6 +46,7 @@ describe('Security UsageCollector', () => { accessAgreementEnabled: false, authProviderCount: 1, enabledAuthProviders: ['basic'], + fipsModeEnabled: false, loginSelectorEnabled: false, httpAuthSchemes: ['apikey', 'bearer'], sessionIdleTimeoutInMinutes: 4320, @@ -106,6 +109,7 @@ describe('Security UsageCollector', () => { accessAgreementEnabled: false, authProviderCount: 0, enabledAuthProviders: [], + fipsModeEnabled: false, loginSelectorEnabled: false, httpAuthSchemes: [], sessionIdleTimeoutInMinutes: 0, @@ -426,6 +430,55 @@ describe('Security UsageCollector', () => { }); }); + describe('fipsMode enabled', () => { + it('reports when fipsMode is enabled', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + fipsMode: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ + isLicenseAvailable: true, + allowFips: true, + }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(collectorFetchContext); + + expect(usage).toEqual({ + ...DEFAULT_USAGE, + fipsModeEnabled: true, + }); + }); + + it('does not report fipsMode when the license does not permit it', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + fipsMode: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowFips: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(collectorFetchContext); + + expect(usage).toEqual({ + ...DEFAULT_USAGE, + fipsModeEnabled: false, + }); + }); + }); + describe('http auth schemes', () => { it('reports customized http auth schemes', async () => { const config = createSecurityConfig( diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts index fc761fb13a50e..575fea2bf32c4 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts @@ -16,6 +16,7 @@ interface Usage { accessAgreementEnabled: boolean; authProviderCount: number; enabledAuthProviders: string[]; + fipsModeEnabled: boolean; httpAuthSchemes: string[]; sessionIdleTimeoutInMinutes: number; sessionLifespanInMinutes: number; @@ -93,6 +94,12 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens }, }, }, + fipsModeEnabled: { + type: 'boolean', + _meta: { + description: 'Indicates if Kibana is being run in FIPS mode.', + }, + }, httpAuthSchemes: { type: 'array', items: { @@ -139,7 +146,8 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens }, }, fetch: () => { - const { allowRbac, allowAccessAgreement, allowAuditLogging } = license.getFeatures(); + const { allowRbac, allowAccessAgreement, allowAuditLogging, allowFips } = + license.getFeatures(); if (!allowRbac) { return { auditLoggingEnabled: false, @@ -147,6 +155,7 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens accessAgreementEnabled: false, authProviderCount: 0, enabledAuthProviders: [], + fipsModeEnabled: false, httpAuthSchemes: [], sessionIdleTimeoutInMinutes: 0, sessionLifespanInMinutes: 0, @@ -171,6 +180,8 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens WELL_KNOWN_AUTH_SCHEMES.includes(scheme.toLowerCase()) ); + const fipsModeEnabled = allowFips && config.fipsMode.enabled; + const sessionExpirations = config.session.getExpirationTimeouts(undefined); // use `undefined` to get global expiration values const sessionIdleTimeoutInMinutes = sessionExpirations.idleTimeout?.asMinutes() ?? 0; const sessionLifespanInMinutes = sessionExpirations.lifespan?.asMinutes() ?? 0; @@ -202,6 +213,7 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens accessAgreementEnabled, authProviderCount, enabledAuthProviders, + fipsModeEnabled, httpAuthSchemes, sessionIdleTimeoutInMinutes, sessionLifespanInMinutes, diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts index 7e419dbe6453c..25c47e838d85c 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts @@ -39,6 +39,37 @@ export const EngineDescriptor = z.object({ error: z.object({}).optional(), }); +export type EngineComponentResource = z.infer; +export const EngineComponentResource = z.enum([ + 'entity_engine', + 'entity_definition', + 'index', + 'component_template', + 'index_template', + 'ingest_pipeline', + 'enrich_policy', + 'task', + 'transform', +]); +export type EngineComponentResourceEnum = typeof EngineComponentResource.enum; +export const EngineComponentResourceEnum = EngineComponentResource.enum; + +export type EngineComponentStatus = z.infer; +export const EngineComponentStatus = z.object({ + id: z.string(), + installed: z.boolean(), + resource: EngineComponentResource, + health: z.enum(['green', 'yellow', 'red', 'unknown']).optional(), + errors: z + .array( + z.object({ + title: z.string().optional(), + message: z.string().optional(), + }) + ) + .optional(), +}); + export type StoreStatus = z.infer; export const StoreStatus = z.enum(['not_installed', 'installing', 'running', 'stopped', 'error']); export type StoreStatusEnum = typeof StoreStatus.enum; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml index 9a42191a556ac..5adb6fe038dc9 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml @@ -42,6 +42,49 @@ components: - updating - error + EngineComponentStatus: + type: object + required: + - id + - installed + - resource + properties: + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + health: + type: string + enum: + - green + - yellow + - red + - unknown + errors: + type: array + items: + type: object + properties: + title: + type: string + message: + type: string + + EngineComponentResource: + type: string + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + StoreStatus: type: string enum: diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts similarity index 78% rename from x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts index 9644a1a333d16..70a58bf02be68 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts @@ -16,13 +16,7 @@ import { z } from '@kbn/zod'; -import { IndexPattern, EngineDescriptor, StoreStatus } from './common.gen'; - -export type GetEntityStoreStatusResponse = z.infer; -export const GetEntityStoreStatusResponse = z.object({ - status: StoreStatus.optional(), - engines: z.array(EngineDescriptor).optional(), -}); +import { IndexPattern, EngineDescriptor } from './common.gen'; export type InitEntityStoreRequestBody = z.infer; export const InitEntityStoreRequestBody = z.object({ diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml similarity index 65% rename from x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml rename to x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml index 306e876dfc4a7..81eec22d9ade9 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml @@ -41,24 +41,3 @@ paths: type: array items: $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' - - /api/entity_store/status: - get: - x-labels: [ess, serverless] - x-codegen-enabled: true - operationId: GetEntityStoreStatus - summary: Get the status of the Entity Store - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - properties: - status: - $ref: './common.schema.yaml#/components/schemas/StoreStatus' - engines: - type: array - items: - $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts index b21308de36f18..32bc0a4efc07b 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts @@ -10,6 +10,5 @@ export * from './get.gen'; export * from './init.gen'; export * from './list.gen'; export * from './start.gen'; -export * from './stats.gen'; export * from './stop.gen'; export * from './apply_dataview_indices.gen'; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts deleted file mode 100644 index 8b2cb44947535..0000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts +++ /dev/null @@ -1,39 +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. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Get Entity Engine stats - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { EntityType, IndexPattern, EngineStatus } from '../common.gen'; - -export type GetEntityEngineStatsRequestParams = z.infer; -export const GetEntityEngineStatsRequestParams = z.object({ - /** - * The entity type of the engine (either 'user' or 'host'). - */ - entityType: EntityType, -}); -export type GetEntityEngineStatsRequestParamsInput = z.input< - typeof GetEntityEngineStatsRequestParams ->; - -export type GetEntityEngineStatsResponse = z.infer; -export const GetEntityEngineStatsResponse = z.object({ - type: EntityType.optional(), - indexPattern: IndexPattern.optional(), - status: EngineStatus.optional(), - transforms: z.array(z.object({})).optional(), - indices: z.array(z.object({})).optional(), -}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml deleted file mode 100644 index 25c010acc92ce..0000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml +++ /dev/null @@ -1,41 +0,0 @@ -openapi: 3.0.0 - -info: - title: Get Entity Engine stats - version: '2023-10-31' -paths: - /api/entity_store/engines/{entityType}/stats: - post: - x-labels: [ess, serverless] - x-codegen-enabled: true - operationId: GetEntityEngineStats - summary: Get Entity Engine stats - parameters: - - name: entityType - in: path - required: true - schema: - $ref: '../common.schema.yaml#/components/schemas/EntityType' - description: The entity type of the engine (either 'user' or 'host'). - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - properties: - type: - $ref : '../common.schema.yaml#/components/schemas/EntityType' - indexPattern: - $ref : '../common.schema.yaml#/components/schemas/IndexPattern' - status: - $ref : '../common.schema.yaml#/components/schemas/EngineStatus' - transforms: - type: array - items: - type: object - indices: - type: array - items: - type: object diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.ts new file mode 100644 index 0000000000000..76249a787a43b --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Enable Entity Store + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; +import { BooleanFromString } from '@kbn/zod-helpers'; + +import { StoreStatus, EngineDescriptor, EngineComponentStatus } from './common.gen'; + +export type GetEntityStoreStatusRequestQuery = z.infer; +export const GetEntityStoreStatusRequestQuery = z.object({ + /** + * If true returns a detailed status of the engine including all it's components + */ + include_components: BooleanFromString.optional(), +}); +export type GetEntityStoreStatusRequestQueryInput = z.input< + typeof GetEntityStoreStatusRequestQuery +>; + +export type GetEntityStoreStatusResponse = z.infer; +export const GetEntityStoreStatusResponse = z.object({ + status: StoreStatus, + engines: z.array( + EngineDescriptor.merge( + z.object({ + components: z.array(EngineComponentStatus).optional(), + }) + ) + ), +}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml new file mode 100644 index 0000000000000..a1be66282328e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml @@ -0,0 +1,44 @@ +openapi: 3.0.0 + +info: + title: Enable Entity Store + version: '2023-10-31' +paths: + /api/entity_store/status: + get: + x-labels: [ess, serverless] + x-codegen-enabled: true + operationId: GetEntityStoreStatus + summary: Get the status of the Entity Store + + parameters: + - name: include_components + in: query + schema: + type: boolean + description: If true returns a detailed status of the engine including all it's components + + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + required: + - status + - engines + properties: + status: + $ref: './common.schema.yaml#/components/schemas/StoreStatus' + engines: + type: array + items: + allOf: + - $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + type: array + items: + $ref: './common.schema.yaml#/components/schemas/EngineComponentStatus' diff --git a/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts index 5a1cf49baecd1..b03a81b3b2249 100644 --- a/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts +++ b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -232,10 +232,9 @@ import type { UploadAssetCriticalityRecordsResponse, } from './entity_analytics/asset_criticality/upload_asset_criticality_csv.gen'; import type { - GetEntityStoreStatusResponse, InitEntityStoreRequestBodyInput, InitEntityStoreResponse, -} from './entity_analytics/entity_store/enablement.gen'; +} from './entity_analytics/entity_store/enable.gen'; import type { ApplyEntityEngineDataviewIndicesResponse } from './entity_analytics/entity_store/engine/apply_dataview_indices.gen'; import type { DeleteEntityEngineRequestQueryInput, @@ -257,10 +256,6 @@ import type { StartEntityEngineRequestParamsInput, StartEntityEngineResponse, } from './entity_analytics/entity_store/engine/start.gen'; -import type { - GetEntityEngineStatsRequestParamsInput, - GetEntityEngineStatsResponse, -} from './entity_analytics/entity_store/engine/stats.gen'; import type { StopEntityEngineRequestParamsInput, StopEntityEngineResponse, @@ -269,6 +264,10 @@ import type { ListEntitiesRequestQueryInput, ListEntitiesResponse, } from './entity_analytics/entity_store/entities/list_entities.gen'; +import type { + GetEntityStoreStatusRequestQueryInput, + GetEntityStoreStatusResponse, +} from './entity_analytics/entity_store/status.gen'; import type { CleanUpRiskEngineResponse } from './entity_analytics/risk_engine/engine_cleanup_route.gen'; import type { DisableRiskEngineResponse } from './entity_analytics/risk_engine/engine_disable_route.gen'; import type { EnableRiskEngineResponse } from './entity_analytics/risk_engine/engine_enable_route.gen'; @@ -353,6 +352,7 @@ import type { CreateRuleMigrationRequestBodyInput, CreateRuleMigrationResponse, GetAllStatsRuleMigrationResponse, + GetRuleMigrationRequestQueryInput, GetRuleMigrationRequestParamsInput, GetRuleMigrationResponse, GetRuleMigrationResourcesRequestQueryInput, @@ -360,6 +360,13 @@ import type { GetRuleMigrationResourcesResponse, GetRuleMigrationStatsRequestParamsInput, GetRuleMigrationStatsResponse, + GetRuleMigrationTranslationStatsRequestParamsInput, + GetRuleMigrationTranslationStatsResponse, + InstallMigrationRulesRequestParamsInput, + InstallMigrationRulesRequestBodyInput, + InstallMigrationRulesResponse, + InstallTranslatedMigrationRulesRequestParamsInput, + InstallTranslatedMigrationRulesResponse, StartRuleMigrationRequestParamsInput, StartRuleMigrationRequestBodyInput, StartRuleMigrationResponse, @@ -1290,19 +1297,7 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } - async getEntityEngineStats(props: GetEntityEngineStatsProps) { - this.log.info(`${new Date().toISOString()} Calling API GetEntityEngineStats`); - return this.kbnClient - .request({ - path: replaceParams('/api/entity_store/engines/{entityType}/stats', props.params), - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - async getEntityStoreStatus() { + async getEntityStoreStatus(props: GetEntityStoreStatusProps) { this.log.info(`${new Date().toISOString()} Calling API GetEntityStoreStatus`); return this.kbnClient .request({ @@ -1311,6 +1306,8 @@ finalize it. [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', }, method: 'GET', + + query: props.query, }) .catch(catchAxiosErrorFormatAndThrow); } @@ -1421,6 +1418,8 @@ finalize it. [ELASTIC_HTTP_VERSION_HEADER]: '1', }, method: 'GET', + + query: props.query, }) .catch(catchAxiosErrorFormatAndThrow); } @@ -1459,6 +1458,24 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Retrieves the translation stats of a SIEM rules migration using the migration id provided + */ + async getRuleMigrationTranslationStats(props: GetRuleMigrationTranslationStatsProps) { + this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationTranslationStats`); + return this.kbnClient + .request({ + path: replaceParams( + '/internal/siem_migrations/rules/{migration_id}/translation_stats', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } /** * Get the details of an existing saved Timeline or Timeline template. */ @@ -1570,6 +1587,22 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Installs migration rules + */ + async installMigrationRules(props: InstallMigrationRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API InstallMigrationRules`); + return this.kbnClient + .request({ + path: replaceParams('/internal/siem_migrations/rules/{migration_id}/install', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } /** * Install and update all Elastic prebuilt detection rules and Timelines. */ @@ -1601,6 +1634,24 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Installs all translated migration rules + */ + async installTranslatedMigrationRules(props: InstallTranslatedMigrationRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API InstallTranslatedMigrationRules`); + return this.kbnClient + .request({ + path: replaceParams( + '/internal/siem_migrations/rules/{migration_id}/install_translated', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } async internalUploadAssetCriticalityRecords(props: InternalUploadAssetCriticalityRecordsProps) { this.log.info(`${new Date().toISOString()} Calling API InternalUploadAssetCriticalityRecords`); return this.kbnClient @@ -2285,8 +2336,8 @@ export interface GetEndpointSuggestionsProps { export interface GetEntityEngineProps { params: GetEntityEngineRequestParamsInput; } -export interface GetEntityEngineStatsProps { - params: GetEntityEngineStatsRequestParamsInput; +export interface GetEntityStoreStatusProps { + query: GetEntityStoreStatusRequestQueryInput; } export interface GetNotesProps { query: GetNotesRequestQueryInput; @@ -2306,6 +2357,7 @@ export interface GetRuleExecutionResultsProps { params: GetRuleExecutionResultsRequestParamsInput; } export interface GetRuleMigrationProps { + query: GetRuleMigrationRequestQueryInput; params: GetRuleMigrationRequestParamsInput; } export interface GetRuleMigrationResourcesProps { @@ -2315,6 +2367,9 @@ export interface GetRuleMigrationResourcesProps { export interface GetRuleMigrationStatsProps { params: GetRuleMigrationStatsRequestParamsInput; } +export interface GetRuleMigrationTranslationStatsProps { + params: GetRuleMigrationTranslationStatsRequestParamsInput; +} export interface GetTimelineProps { query: GetTimelineRequestQueryInput; } @@ -2335,9 +2390,16 @@ export interface InitEntityEngineProps { export interface InitEntityStoreProps { body: InitEntityStoreRequestBodyInput; } +export interface InstallMigrationRulesProps { + params: InstallMigrationRulesRequestParamsInput; + body: InstallMigrationRulesRequestBodyInput; +} export interface InstallPrepackedTimelinesProps { body: InstallPrepackedTimelinesRequestBodyInput; } +export interface InstallTranslatedMigrationRulesProps { + params: InstallTranslatedMigrationRulesRequestParamsInput; +} export interface InternalUploadAssetCriticalityRecordsProps { attachment: FormData; } diff --git a/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts b/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts new file mode 100644 index 0000000000000..11cbc1bfd7cd8 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Moment } from 'moment'; + +import type { DefendInsightType } from '@kbn/elastic-assistant-common'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export enum Category { + Endpoint = 'endpoint', +} + +export enum SourceType { + LlmConnector = 'llm-connector', +} + +export enum TargetType { + Endpoint = 'endpoint', +} + +export enum ActionType { + Refreshed = 'refreshed', // new or refreshed + Remediated = 'remediated', + Suppressed = 'suppressed', // temporarily supressed, can be refreshed + Dismissed = 'dismissed', // "permanently" dismissed, cannot be normally refreshed +} + +export type ExceptionListRemediationType = Pick< + ExceptionListItemSchema, + 'list_id' | 'name' | 'description' | 'entries' | 'tags' | 'os_types' +>; + +export interface SecurityWorkflowInsight { + id?: string; + '@timestamp': Moment; + message: string; + category: Category; + type: DefendInsightType; + source: { + type: SourceType; + id: string; + data_range_start: Moment; + data_range_end: Moment; + }; + target: { + type: TargetType; + ids: string[]; + }; + action: { + type: ActionType; + timestamp: Moment; + }; + value: string; + remediation: { + exception_list_items?: ExceptionListRemediationType[]; + }; + metadata: { + notes?: Record; + message_variables?: string[]; + }; +} + +export interface SearchParams { + size?: number; + from?: number; + ids?: string[]; + categories?: Category[]; + types?: DefendInsightType[]; + sourceTypes?: SourceType[]; + sourceIds?: string[]; + targetTypes?: TargetType[]; + targetIds?: string[]; + actionTypes: ActionType[]; +} diff --git a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts index 8a2d6cf3775c9..a910cb90f1664 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; + export const SIEM_MIGRATIONS_PATH = '/internal/siem_migrations' as const; export const SIEM_RULE_MIGRATIONS_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as const; @@ -13,10 +15,22 @@ export const SIEM_RULE_MIGRATION_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/{migration export const SIEM_RULE_MIGRATION_START_PATH = `${SIEM_RULE_MIGRATION_PATH}/start` as const; export const SIEM_RULE_MIGRATION_RETRY_PATH = `${SIEM_RULE_MIGRATION_PATH}/retry` as const; export const SIEM_RULE_MIGRATION_STATS_PATH = `${SIEM_RULE_MIGRATION_PATH}/stats` as const; +export const SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH = + `${SIEM_RULE_MIGRATION_PATH}/translation_stats` as const; export const SIEM_RULE_MIGRATION_STOP_PATH = `${SIEM_RULE_MIGRATION_PATH}/stop` as const; +export const SIEM_RULE_MIGRATION_INSTALL_PATH = `${SIEM_RULE_MIGRATION_PATH}/install` as const; +export const SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH = + `${SIEM_RULE_MIGRATION_PATH}/install_translated` as const; export const SIEM_RULE_MIGRATION_RESOURCES_PATH = `${SIEM_RULE_MIGRATION_PATH}/resources` as const; +export enum SiemMigrationTaskStatus { + READY = 'ready', + RUNNING = 'running', + STOPPED = 'stopped', + FINISHED = 'finished', +} + export enum SiemMigrationStatus { PENDING = 'pending', PROCESSING = 'processing', @@ -29,3 +43,6 @@ export enum SiemMigrationRuleTranslationResult { PARTIAL = 'partial', UNTRANSLATABLE = 'untranslatable', } + +export const DEFAULT_TRANSLATION_RISK_SCORE = 21; +export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low'; diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts index 36728e0e928a0..aa69f3b3c27f0 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts @@ -24,6 +24,7 @@ import { RuleMigrationComments, RuleMigrationTaskStats, RuleMigration, + RuleMigrationTranslationStats, RuleMigrationResourceData, RuleMigrationResourceType, RuleMigrationResource, @@ -44,6 +45,13 @@ export const CreateRuleMigrationResponse = z.object({ export type GetAllStatsRuleMigrationResponse = z.infer; export const GetAllStatsRuleMigrationResponse = z.array(RuleMigrationTaskStats); +export type GetRuleMigrationRequestQuery = z.infer; +export const GetRuleMigrationRequestQuery = z.object({ + page: z.coerce.number().optional(), + per_page: z.coerce.number().optional(), + search_term: z.string().optional(), +}); +export type GetRuleMigrationRequestQueryInput = z.input; export type GetRuleMigrationRequestParams = z.infer; export const GetRuleMigrationRequestParams = z.object({ @@ -52,7 +60,13 @@ export const GetRuleMigrationRequestParams = z.object({ export type GetRuleMigrationRequestParamsInput = z.input; export type GetRuleMigrationResponse = z.infer; -export const GetRuleMigrationResponse = z.array(RuleMigration); +export const GetRuleMigrationResponse = z.object({ + /** + * The total number of rules in migration. + */ + total: z.number(), + data: z.array(RuleMigration), +}); export type GetRuleMigrationResourcesRequestQuery = z.infer< typeof GetRuleMigrationResourcesRequestQuery >; @@ -88,6 +102,63 @@ export type GetRuleMigrationStatsRequestParamsInput = z.input< export type GetRuleMigrationStatsResponse = z.infer; export const GetRuleMigrationStatsResponse = RuleMigrationTaskStats; +export type GetRuleMigrationTranslationStatsRequestParams = z.infer< + typeof GetRuleMigrationTranslationStatsRequestParams +>; +export const GetRuleMigrationTranslationStatsRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type GetRuleMigrationTranslationStatsRequestParamsInput = z.input< + typeof GetRuleMigrationTranslationStatsRequestParams +>; + +export type GetRuleMigrationTranslationStatsResponse = z.infer< + typeof GetRuleMigrationTranslationStatsResponse +>; +export const GetRuleMigrationTranslationStatsResponse = RuleMigrationTranslationStats; + +export type InstallMigrationRulesRequestParams = z.infer; +export const InstallMigrationRulesRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type InstallMigrationRulesRequestParamsInput = z.input< + typeof InstallMigrationRulesRequestParams +>; + +export type InstallMigrationRulesRequestBody = z.infer; +export const InstallMigrationRulesRequestBody = z.array(NonEmptyString); +export type InstallMigrationRulesRequestBodyInput = z.input< + typeof InstallMigrationRulesRequestBody +>; + +export type InstallMigrationRulesResponse = z.infer; +export const InstallMigrationRulesResponse = z.object({ + /** + * Indicates rules migrations have been installed. + */ + installed: z.boolean(), +}); + +export type InstallTranslatedMigrationRulesRequestParams = z.infer< + typeof InstallTranslatedMigrationRulesRequestParams +>; +export const InstallTranslatedMigrationRulesRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type InstallTranslatedMigrationRulesRequestParamsInput = z.input< + typeof InstallTranslatedMigrationRulesRequestParams +>; + +export type InstallTranslatedMigrationRulesResponse = z.infer< + typeof InstallTranslatedMigrationRulesResponse +>; +export const InstallTranslatedMigrationRulesResponse = z.object({ + /** + * Indicates rules migrations have been installed. + */ + installed: z.boolean(), +}); + export type StartRuleMigrationRequestParams = z.infer; export const StartRuleMigrationRequestParams = z.object({ migration_id: NonEmptyString, @@ -167,16 +238,7 @@ export type UpsertRuleMigrationResourcesRequestParamsInput = z.input< export type UpsertRuleMigrationResourcesRequestBody = z.infer< typeof UpsertRuleMigrationResourcesRequestBody >; -export const UpsertRuleMigrationResourcesRequestBody = z.array( - RuleMigrationResourceData.merge( - z.object({ - /** - * The rule resource migration id - */ - id: NonEmptyString, - }) - ) -); +export const UpsertRuleMigrationResourcesRequestBody = z.array(RuleMigrationResourceData); export type UpsertRuleMigrationResourcesRequestBodyInput = z.input< typeof UpsertRuleMigrationResourcesRequestBody >; diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml index fdb589e7b45cd..a062b75d41699 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml @@ -10,6 +10,7 @@ paths: summary: Creates a new rule migration operationId: CreateRuleMigration x-codegen-enabled: true + x-internal: true description: Creates a new SIEM rules migration using the original vendor rules provided tags: - SIEM Rule Migrations @@ -39,6 +40,7 @@ paths: summary: Updates rules migrations operationId: UpdateRuleMigration x-codegen-enabled: true + x-internal: true description: Updates rules migrations attributes tags: - SIEM Rule Migrations @@ -79,11 +81,79 @@ paths: type: boolean description: Indicates rules migrations have been updated. + /internal/siem_migrations/rules/{migration_id}/install: + post: + summary: Installs translated migration rules + operationId: InstallMigrationRules + x-codegen-enabled: true + description: Installs migration rules + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to isnstall rules for + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + description: The rule migration id + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates rules migrations have been installed correctly. + content: + application/json: + schema: + type: object + required: + - installed + properties: + installed: + type: boolean + description: Indicates rules migrations have been installed. + + /internal/siem_migrations/rules/{migration_id}/install_translated: + post: + summary: Installs all translated migration rules + operationId: InstallTranslatedMigrationRules + x-codegen-enabled: true + description: Installs all translated migration rules + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to install translated rules for + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates rules migrations have been installed correctly. + content: + application/json: + schema: + type: object + required: + - installed + properties: + installed: + type: boolean + description: Indicates rules migrations have been installed. + /internal/siem_migrations/rules/stats: get: summary: Retrieves the stats for all rule migrations operationId: GetAllStatsRuleMigration x-codegen-enabled: true + x-internal: true description: Retrieves the rule migrations stats for all migrations stored in the system tags: - SIEM Rule Migrations @@ -104,6 +174,7 @@ paths: summary: Retrieves all the rules of a migration operationId: GetRuleMigration x-codegen-enabled: true + x-internal: true description: Retrieves the rule documents stored in the system given the rule migration id tags: - SIEM Rule Migrations @@ -114,15 +185,40 @@ paths: schema: description: The migration id to start $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + - name: page + in: query + required: false + schema: + type: number + - name: per_page + in: query + required: false + schema: + type: number + - name: search_term + in: query + required: false + schema: + type: string + responses: 200: description: Indicates rule migration have been retrieved correctly. content: application/json: schema: - type: array - items: - $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigration' + type: object + required: + - total + - data + properties: + total: + type: number + description: The total number of rules in migration. + data: + type: array + items: + $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigration' 204: description: Indicates the migration id was not found. @@ -131,6 +227,7 @@ paths: summary: Starts a rule migration operationId: StartRuleMigration x-codegen-enabled: true + x-internal: true description: Starts a SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -175,6 +272,7 @@ paths: summary: Gets a rule migration task stats operationId: GetRuleMigrationStats x-codegen-enabled: true + x-internal: true description: Retrieves the stats of a SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -183,7 +281,7 @@ paths: in: path required: true schema: - description: The migration id to start + description: The migration id to fetch stats for $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' responses: 200: @@ -195,11 +293,37 @@ paths: 204: description: Indicates the migration id was not found. + /internal/siem_migrations/rules/{migration_id}/translation_stats: + get: + summary: Gets a rule migration translation stats + operationId: GetRuleMigrationTranslationStats + x-codegen-enabled: true + description: Retrieves the translation stats of a SIEM rules migration using the migration id provided + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to fetch translation stats for + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates the migration stats has been retrieved correctly. + content: + application/json: + schema: + $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationTranslationStats' + 204: + description: Indicates the migration id was not found. + /internal/siem_migrations/rules/{migration_id}/stop: put: summary: Stops an existing rule migration operationId: StopRuleMigration x-codegen-enabled: true + x-internal: true description: Stops a running SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -233,6 +357,7 @@ paths: summary: Creates or updates rule migration resources for a migration operationId: UpsertRuleMigrationResources x-codegen-enabled: true + x-internal: true description: Creates or updates resources for an existing SIEM rules migration tags: - SIEM Rule Migrations @@ -251,15 +376,7 @@ paths: schema: type: array items: - allOf: - - $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData' - - type: object - required: - - id - properties: - id: - description: The rule resource migration id - $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData' responses: 200: description: Indicates migration resources have been created or updated correctly. @@ -278,6 +395,7 @@ paths: summary: Gets rule migration resources for a migration operationId: GetRuleMigrationResources x-codegen-enabled: true + x-internal: true description: Retrieves resources for an existing SIEM rules migration tags: - SIEM Rule Migrations diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts index 2260b83190e22..61706077d9549 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts @@ -113,7 +113,7 @@ export type RuleMigrationTranslationResultEnum = typeof RuleMigrationTranslation export const RuleMigrationTranslationResultEnum = RuleMigrationTranslationResult.enum; /** - * The status of the rule migration process. + * The status of each rule migration. */ export type RuleMigrationStatus = z.infer; export const RuleMigrationStatus = z.enum(['pending', 'processing', 'completed', 'failed']); @@ -186,6 +186,14 @@ export const RuleMigration = z }) .merge(RuleMigrationData); +/** + * The status of the migration task. + */ +export type RuleMigrationTaskStatus = z.infer; +export const RuleMigrationTaskStatus = z.enum(['ready', 'running', 'stopped', 'finished']); +export type RuleMigrationTaskStatusEnum = typeof RuleMigrationTaskStatus.enum; +export const RuleMigrationTaskStatusEnum = RuleMigrationTaskStatus.enum; + /** * The rule migration task stats object. */ @@ -198,7 +206,7 @@ export const RuleMigrationTaskStats = z.object({ /** * Indicates if the migration task status. */ - status: z.enum(['ready', 'running', 'stopped', 'finished']), + status: RuleMigrationTaskStatus, /** * The rules migration stats. */ @@ -234,6 +242,38 @@ export const RuleMigrationTaskStats = z.object({ last_updated_at: z.string(), }); +/** + * The rule migration translation stats object. + */ +export type RuleMigrationTranslationStats = z.infer; +export const RuleMigrationTranslationStats = z.object({ + /** + * The migration id + */ + id: NonEmptyString, + /** + * The rules migration translation stats. + */ + rules: z.object({ + /** + * The total number of rules to migrate. + */ + total: z.number().int(), + /** + * The number of rules that matched Elastic prebuilt rules. + */ + prebuilt: z.number().int(), + /** + * The number of rules that did not match Elastic prebuilt rules and will be installed as custom rules. + */ + custom: z.number().int(), + /** + * The number of rules that can be installed. + */ + installable: z.number().int(), + }), +}); + /** * The type of the rule migration resource. */ diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml index 17c70665b9ad3..fdcbb7b04515a 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml @@ -155,13 +155,8 @@ components: description: The migration id $ref: './common.schema.yaml#/components/schemas/NonEmptyString' status: - type: string description: Indicates if the migration task status. - enum: - - ready - - running - - stopped - - finished + $ref: '#/components/schemas/RuleMigrationTaskStatus' rules: type: object description: The rules migration stats. @@ -194,6 +189,47 @@ components: type: string description: The moment of the last update. + RuleMigrationTaskStatus: + type: string + description: The status of the migration task. + enum: # should match SiemMigrationTaskStatus enum at ../constants.ts + - ready + - running + - stopped + - finished + + RuleMigrationTranslationStats: + type: object + description: The rule migration translation stats object. + required: + - id + - rules + properties: + id: + description: The migration id + $ref: './common.schema.yaml#/components/schemas/NonEmptyString' + rules: + type: object + description: The rules migration translation stats. + required: + - total + - prebuilt + - custom + - installable + properties: + total: + type: integer + description: The total number of rules to migrate. + prebuilt: + type: integer + description: The number of rules that matched Elastic prebuilt rules. + custom: + type: integer + description: The number of rules that did not match Elastic prebuilt rules and will be installed as custom rules. + installable: + type: integer + description: The number of rules that can be installed. + RuleMigrationTranslationResult: type: string description: The rule translation result. @@ -204,7 +240,7 @@ components: RuleMigrationStatus: type: string - description: The status of the rule migration process. + description: The status of each rule migration. enum: # should match SiemMigrationsStatus enum at ../constants.ts - pending - processing diff --git a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts index 8435e6ec89845..91c426c24dc78 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts @@ -13,6 +13,10 @@ import type { BrowserFields, TimelineNonEcsData } from '../../../search_strategy /** The following props are provided to the function called by `renderCellValue` */ export type CellValueElementProps = EuiDataGridCellValueElementProps & { + /** + * makes sure that field is not rendered as a plain text + * but according to the renderer. + */ asPlainText?: boolean; browserFields?: BrowserFields; data: TimelineNonEcsData[]; diff --git a/x-pack/plugins/security_solution/common/types/timeline/store.ts b/x-pack/plugins/security_solution/common/types/timeline/store.ts index c65705e0c9a74..834949d2ed591 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/store.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/store.ts @@ -73,7 +73,7 @@ export type OnColumnRemoved = (columnId: ColumnId) => void; export type OnColumnResized = ({ columnId, delta }: { columnId: ColumnId; delta: number }) => void; /** Invoked when a user clicks to load more item */ -export type OnChangePage = (nextPage: number) => void; +export type OnFetchMoreRecords = (nextPage: number) => void; /** Invoked when a user checks/un-checks a row */ export type OnRowSelected = ({ diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index fa79b170f3513..b1b85b8222786 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -430,41 +430,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/EntityType' - responses: - '200': - content: - application/json: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -615,6 +580,14 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: >- + If true returns a detailed status of the engine including all it's + components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -624,10 +597,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/EngineDescriptor' + allOf: + - $ref: '#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -824,6 +807,47 @@ components: $ref: '#/components/schemas/AssetCriticalityLevel' required: - criticality_level + EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + required: + - id + - installed + - resource EngineDataviewUpdateResult: type: object properties: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index 9c2b3d62b1650..4a3b3495467e9 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -430,41 +430,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/EntityType' - responses: - '200': - content: - application/json: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -615,6 +580,14 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: >- + If true returns a detailed status of the engine including all it's + components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -624,10 +597,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/EngineDescriptor' + allOf: + - $ref: '#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -824,6 +807,47 @@ components: $ref: '#/components/schemas/AssetCriticalityLevel' required: - criticality_level + EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + required: + - id + - installed + - resource EngineDataviewUpdateResult: type: object properties: diff --git a/x-pack/plugins/security_solution/docs/siem_migration/README.md b/x-pack/plugins/security_solution/docs/siem_migration/README.md new file mode 100644 index 0000000000000..84a2d17277ec4 --- /dev/null +++ b/x-pack/plugins/security_solution/docs/siem_migration/README.md @@ -0,0 +1,17 @@ +# SIEM Migration Library + +## Migration Process + +The SIEM migration library defines a set of UI components and services that are used to migrate third party SIEM resources like detection rules and translate them into resources that can be used in the Elastic Security app. + +## Graphs: + +The below images are generated by running the following command from the security_solution directory: + +```bash +yarn siem-migrations:graph:draw +``` + +Main agent graph: + +![Agent Graph](./img/agent_graph.png) \ No newline at end of file diff --git a/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png b/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png new file mode 100644 index 0000000000000..ecccb602e2016 Binary files /dev/null and b/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png differ diff --git a/x-pack/plugins/security_solution/kibana.jsonc b/x-pack/plugins/security_solution/kibana.jsonc index 0e713bc095888..f672378c88df8 100644 --- a/x-pack/plugins/security_solution/kibana.jsonc +++ b/x-pack/plugins/security_solution/kibana.jsonc @@ -25,7 +25,6 @@ "dashboard", "data", "dataViews", - "discover", "ecsDataQualityDashboard", "elasticAssistant", "embeddable", @@ -59,7 +58,8 @@ "unifiedDocViewer", "charts", "entityManager", - "inference" + "inference", + "discoverShared" ], "optionalPlugins": [ "encryptedSavedObjects", diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index 62a406960ceeb..fd1be833c5d6b 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -27,6 +27,7 @@ "test:generate:serverless-dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 node --no-warnings scripts/endpoint/resolver_generator --node https://elastic_serverless:changeme@127.0.0.1:9200 --kibana http://elastic_serverless:changeme@127.0.0.1:5601", "mappings:generate": "node scripts/mappings/mappings_generator", "mappings:load": "node scripts/mappings/mappings_loader", + "siem-migrations:graph:draw": "node scripts/siem_migration/draw_graphs", "junit:transform": "node scripts/junit_transformer --pathPattern '../../../target/kibana-security-solution/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Security Solution Cypress' --writeInPlace", "openapi:generate": "node scripts/openapi/generate", "openapi:generate:debug": "node --inspect-brk scripts/openapi/generate", @@ -35,4 +36,4 @@ "openapi:bundle:entity-analytics": "node scripts/openapi/bundle_entity_analytics", "openapi:bundle:endpoint-management": "node scripts/openapi/bundle_endpoint_management" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts index 429d1e1f9db2a..27b309b2acee4 100644 --- a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts +++ b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts @@ -6,8 +6,8 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; -import { isInSecurityApp } from '../../utils'; import type { StartServices } from '../../../../types'; import { createAddToTimelineCellActionFactory } from '../cell_action/add_to_timeline'; diff --git a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts index 3ccbd30efd614..8792d2a6004f5 100644 --- a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts +++ b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts @@ -10,12 +10,13 @@ import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import { apiPublishesUnifiedSearch } from '@kbn/presentation-publishing'; import { isLensApi } from '@kbn/lens-plugin/public'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { KibanaServices } from '../../../../common/lib/kibana'; import type { SecurityAppStore } from '../../../../common/store/types'; import { addProvider } from '../../../../timelines/store/actions'; import type { DataProvider } from '../../../../../common/types'; import { EXISTS_OPERATOR, TimelineId } from '../../../../../common/types'; -import { fieldHasCellActions, isInSecurityApp } from '../../utils'; +import { fieldHasCellActions } from '../../utils'; import { ADD_TO_TIMELINE, ADD_TO_TIMELINE_FAILED_TEXT, diff --git a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts index 7a2c39717b342..ba92d46e6eb81 100644 --- a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts +++ b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts @@ -6,7 +6,7 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; -import { isInSecurityApp } from '../../utils'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { StartServices } from '../../../../types'; import { createCopyToClipboardCellActionFactory } from '../cell_action/copy_to_clipboard'; diff --git a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts index 8546f0c3260cc..f4c61c1e7bf7b 100644 --- a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts +++ b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts @@ -9,8 +9,9 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import copy from 'copy-to-clipboard'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { KibanaServices } from '../../../../common/lib/kibana'; -import { fieldHasCellActions, isCountField, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions, isCountField, isLensEmbeddable } from '../../utils'; import { COPY_TO_CLIPBOARD, COPY_TO_CLIPBOARD_ICON, COPY_TO_CLIPBOARD_SUCCESS } from '../constants'; export const ACTION_ID = 'embeddable_copyToClipboard'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts index d0cdaed61f8a2..19ae6cf1f1748 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts @@ -6,8 +6,8 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; -import { isInSecurityApp } from '../../utils'; import type { StartServices } from '../../../../types'; import { createFilterInCellActionFactory } from '../cell_action/filter_in'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts index 757b2f41d99b5..77e463c5268d4 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts @@ -6,7 +6,7 @@ */ import type { CellActionFactory, CellAction } from '@kbn/cell-actions'; -import { isInSecurityApp } from '../../utils'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; import type { StartServices } from '../../../../types'; import { createFilterOutCellActionFactory } from '../cell_action/filter_out'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts b/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts index 966efe9590ecc..e264466767287 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts @@ -16,8 +16,9 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { createAction } from '@kbn/ui-actions-plugin/public'; import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations'; import { i18n } from '@kbn/i18n'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { timelineSelectors } from '../../../../timelines/store'; -import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions, isLensEmbeddable } from '../../utils'; import { TimelineId } from '../../../../../common/types'; import { DefaultCellActionTypes } from '../../constants'; import type { SecurityAppStore } from '../../../../common/store'; diff --git a/x-pack/plugins/security_solution/public/app/actions/utils.ts b/x-pack/plugins/security_solution/public/app/actions/utils.ts index d857c54d5091f..3da597db60c0e 100644 --- a/x-pack/plugins/security_solution/public/app/actions/utils.ts +++ b/x-pack/plugins/security_solution/public/app/actions/utils.ts @@ -7,7 +7,6 @@ import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; import { isLensApi } from '@kbn/lens-plugin/public'; import type { Serializable } from '@kbn/utility-types'; -import { APP_UI_ID } from '../../../common/constants'; // All cell actions are disabled for these fields in Security const FIELDS_WITHOUT_CELL_ACTIONS = [ @@ -17,10 +16,6 @@ const FIELDS_WITHOUT_CELL_ACTIONS = [ 'kibana.alert.reason', ]; -export const isInSecurityApp = (currentAppId?: string): boolean => { - return !!currentAppId && currentAppId === APP_UI_ID; -}; - // @TODO: this is a temporary fix. It needs a better refactor on the consumer side here to // adapt to the new Embeddable architecture export const isLensEmbeddable = (embeddable: IEmbeddable): embeddable is IEmbeddable => { diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx index adb952d661214..1bf997eb4de2f 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx @@ -12,7 +12,6 @@ import { import { APP_UI_ID } from '../../../../common'; import * as i18n from './translations'; import { - KNOWLEDGE_BASE_CATEGORY, PROMPT_CONTEXT_ALERT_CATEGORY, PROMPT_CONTEXT_DETECTION_RULES_CATEGORY, PROMPT_CONTEXT_EVENT_CATEGORY, @@ -34,16 +33,6 @@ export const BASE_SECURITY_QUICK_PROMPTS: PromptResponse[] = [ promptType: PromptTypeEnum.quick, consumer: APP_UI_ID, }, - { - name: i18n.ESQL_QUERY_GENERATION_TITLE, - content: i18n.ESQL_QUERY_GENERATION_PROMPT, - color: '#9170B8', - categories: [KNOWLEDGE_BASE_CATEGORY], - isDefault: true, - id: i18n.ESQL_QUERY_GENERATION_TITLE, - promptType: PromptTypeEnum.quick, - consumer: APP_UI_ID, - }, { name: i18n.RULE_CREATION_TITLE, content: i18n.RULE_CREATION_PROMPT, diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts index 41b9e7ddb197b..1d122b0169be2 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts @@ -22,21 +22,6 @@ export const ALERT_SUMMARIZATION_PROMPT = i18n.translate( } ); -export const ESQL_QUERY_GENERATION_TITLE = i18n.translate( - 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle', - { - defaultMessage: 'ES|QL Query Generation', - } -); - -export const ESQL_QUERY_GENERATION_PROMPT = i18n.translate( - 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt', - { - defaultMessage: - "As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, check your knowledge really well on all the functions I am asking for. For ES|QL answers specifically, you should only ever answer with what's available in your private knowledge. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema and Elastic Agent.\n\nEnsure the answers are formatted in a way which is easily copyable as a separate code block in markdown.", - } -); - export const RULE_CREATION_TITLE = i18n.translate( 'xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle', { diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx index 97bec48eaaae6..1976d97c9c8d5 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx @@ -6,9 +6,11 @@ */ import type { AttackDiscovery, Replacements } from '@kbn/elastic-assistant-common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import React, { useMemo } from 'react'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { ALERTS_TABLE_REGISTRY_CONFIG_IDS } from '../../../../../../../common/constants'; import { useKibana } from '../../../../../../common/lib/kibana'; @@ -39,12 +41,13 @@ const AlertsTabComponent: React.FC = ({ attackDiscovery, replacements }) const configId = ALERTS_TABLE_REGISTRY_CONFIG_IDS.CASE; // show the same row-actions as in the case view - const alertStateProps = useMemo( + const alertStateProps: AlertsTableStateProps = useMemo( () => ({ alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry, configurationId: configId, id: `attack-discovery-alerts-${attackDiscovery.id}`, - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: SECURITY_SOLUTION_RULE_TYPE_IDS, + consumers: [AlertConsumers.SIEM], query: alertIdsQuery, showAlertStatusWithFlapping: false, }), diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx index 6567fb41a93f4..2b1a2002667c2 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx @@ -19,6 +19,8 @@ import { METRIC_TYPE } from '@kbn/analytics'; import { buildEntityAlertsQuery } from '@kbn/cloud-security-posture-common/utils/helpers'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { TableId } from '@kbn/securitysolution-data-table'; +import type { AlertsByStatus } from '../../../overview/components/detection_response/alerts_by_status/types'; +import { DETECTION_RESPONSE_ALERTS_BY_STATUS_ID } from '../../../overview/components/detection_response/alerts_by_status/types'; import { OPEN_IN_ALERTS_TITLE_HOSTNAME, OPEN_IN_ALERTS_TITLE_STATUS, @@ -34,6 +36,7 @@ import { getSeverityColor } from '../../../detections/components/alerts_kpis/sev import { SeverityBadge } from '../../../common/components/severity_badge'; import { ALERT_PREVIEW_BANNER } from '../../../flyout/document_details/preview/constants'; import { FILTER_OPEN, FILTER_ACKNOWLEDGED } from '../../../../common/types'; +import { useNonClosedAlerts } from '../../hooks/use_non_closed_alerts'; type AlertSeverity = 'low' | 'medium' | 'high' | 'critical'; @@ -68,6 +71,8 @@ export const AlertsDetailsTable = memo( ); }, []); + const [currentFilter, setCurrentFilter] = useState(''); + const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -89,12 +94,46 @@ export const AlertsDetailsTable = memo( const { to, from } = useGlobalTime(); const { signalIndexName } = useSignalIndex(); - const { data } = useQueryAlerts({ - query: buildEntityAlertsQuery(field, to, from, value, 500), + const { data, setQuery } = useQueryAlerts({ + query: buildEntityAlertsQuery(field, to, from, value, 500, ''), queryName: ALERTS_QUERY_NAMES.BY_RULE_BY_STATUS, indexName: signalIndexName, }); + const { filteredAlertsData: alertsData } = useNonClosedAlerts({ + field, + value, + to, + from, + queryId: `${DETECTION_RESPONSE_ALERTS_BY_STATUS_ID}`, + }); + + const severityMap = new Map(); + (Object.keys(alertsData || {}) as AlertsByStatus[]).forEach((status) => { + if (alertsData?.[status]?.severities) { + alertsData?.[status]?.severities.forEach((severity) => { + const currentSeverity = severityMap.get(severity.key) || 0; + severityMap.set(severity.key, currentSeverity + severity.value); + }); + } + }); + + const alertStats = Array.from(severityMap, ([key, count]) => ({ + key: capitalize(key), + count, + color: getSeverityColor(key), + filter: () => { + setCurrentFilter(key); + setQuery(buildEntityAlertsQuery(field, to, from, value, 500, key)); + }, + isCurrentFilter: currentFilter === key, + reset: (event: React.MouseEvent) => { + setCurrentFilter(''); + setQuery(buildEntityAlertsQuery(field, to, from, value, 500, '')); + event?.stopPropagation(); + }, + })); + const alertDataResults = (data?.hits?.hits as AlertsDetailsFields[])?.map( (item: AlertsDetailsFields) => { return { @@ -108,19 +147,6 @@ export const AlertsDetailsTable = memo( } ); - const severitiesMap = alertDataResults?.map((item) => item.severity) || []; - - const alertStats = Object.entries( - severitiesMap.reduce((acc: Record, item) => { - acc[item] = (acc[item] || 0) + 1; - return acc; - }, {}) - ).map(([key, count]) => ({ - key: capitalize(key), - count, - color: getSeverityColor(key), - })); - const { pageOfItems, totalItemCount } = alertsPagination(alertDataResults || []); const pagination = { diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx index 00430c2b87262..61c89e196a183 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx @@ -10,8 +10,12 @@ import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; import { EuiSpacer, EuiPanel, EuiText, EuiBasicTable, EuiIcon } from '@elastic/eui'; import { useMisconfigurationFindings } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_findings'; import { i18n } from '@kbn/i18n'; -import type { CspFinding, CspFindingResult } from '@kbn/cloud-security-posture-common'; -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { + MISCONFIGURATION_STATUS, + type CspFinding, + type CspFindingResult, + buildMisconfigurationEntityFlyoutPreviewQuery, +} from '@kbn/cloud-security-posture-common'; import { euiThemeVars } from '@kbn/ui-theme'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common/schema/rules/latest'; @@ -25,11 +29,17 @@ import { import { METRIC_TYPE } from '@kbn/analytics'; import { useGetNavigationUrlParams } from '@kbn/cloud-security-posture/src/hooks/use_get_navigation_url_params'; import { SecurityPageName } from '@kbn/deeplinks-security'; +import { useHasMisconfigurations } from '@kbn/cloud-security-posture/src/hooks/use_has_misconfigurations'; import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; type MisconfigurationFindingDetailFields = Pick; -const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: number) => { +const getFindingsStats = ( + passedFindingsStats: number, + failedFindingsStats: number, + filterFunction: (filter: string) => void, + currentFilter: string +) => { if (passedFindingsStats === 0 && failedFindingsStats === 0) return []; return [ { @@ -41,6 +51,14 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb ), count: passedFindingsStats, color: euiThemeVars.euiColorSuccess, + filter: () => { + filterFunction(MISCONFIGURATION_STATUS.PASSED); + }, + isCurrentFilter: currentFilter === MISCONFIGURATION_STATUS.PASSED, + reset: (event: React.MouseEvent) => { + filterFunction(''); + event?.stopPropagation(); + }, }, { key: i18n.translate( @@ -51,6 +69,14 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb ), count: failedFindingsStats, color: euiThemeVars.euiColorVis9, + filter: () => { + filterFunction(MISCONFIGURATION_STATUS.FAILED); + }, + isCurrentFilter: currentFilter === MISCONFIGURATION_STATUS.FAILED, + reset: (event: React.MouseEvent) => { + filterFunction(''); + event?.stopPropagation(); + }, }, ]; }; @@ -67,15 +93,16 @@ export const MisconfigurationFindingsDetailsTable = memo( ); }, []); + const [currentFilter, setCurrentFilter] = useState(''); + const { data } = useMisconfigurationFindings({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildMisconfigurationEntityFlyoutPreviewQuery(field, value, currentFilter), sort: [], enabled: true, pageSize: 1, }); - const passedFindings = data?.count.passed || 0; - const failedFindings = data?.count.failed || 0; + const { passedFindings, failedFindings } = useHasMisconfigurations(field, value); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -129,6 +156,13 @@ export const MisconfigurationFindingsDetailsTable = memo( const linkWidth = 40; const resultWidth = 74; + const misconfgurationStats = getFindingsStats( + passedFindings, + failedFindings, + setCurrentFilter, + currentFilter + ); + const columns: Array> = [ { field: 'rule', @@ -202,7 +236,7 @@ export const MisconfigurationFindingsDetailsTable = memo( - + (''); + const { data } = useVulnerabilitiesFindings({ - query: buildEntityFlyoutPreviewQuery('host.name', value), + query: buildVulnerabilityEntityFlyoutPreviewQuery('host.name', value, currentFilter), sort: [], enabled: true, pageSize: 1, }); - const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; + const { counts } = useHasVulnerabilities('host.name', value); + + const { critical = 0, high = 0, medium = 0, low = 0, none = 0 } = counts || {}; const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -120,6 +127,18 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: str ); }; + const vulnerabilityStats = getVulnerabilityStats( + { + critical, + high, + medium, + low, + none, + }, + setCurrentFilter, + currentFilter + ); + const columns: Array> = [ { field: 'vulnerability', @@ -220,15 +239,7 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: str - + { + return !!currentAppId && currentAppId === APP_UI_ID; +}; + +export const useIsInSecurityApp = () => { + const { + services: { application }, + } = useKibana(); + + const currentAppId = useObservable(application.currentAppId$); + + return useMemo(() => isInSecurityApp(currentAppId), [currentAppId]); +}; diff --git a/x-pack/plugins/security_solution/public/common/icons/siem_migrations.tsx b/x-pack/plugins/security_solution/public/common/icons/siem_migrations.tsx new file mode 100644 index 0000000000000..072b0acf9d30a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/icons/siem_migrations.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const SiemMigrationsIcon: React.FC> = ({ ...props }) => ( + + + + + + + + + + + + + + +); diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts deleted file mode 100644 index 5879e2a256cce..0000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act, renderHook } from '@testing-library/react-hooks'; -import { useSetFieldValueWithCallback } from './use_set_field_value_cb'; - -const initialValue = 'initial value'; -const newValue = 'new value'; -const callback = jest.fn(); -const initialProps = { field: 'theField', setFieldValue: () => {}, value: initialValue }; - -describe('set field value callback', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it('invokes the callback after value is set', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender({ ...initialProps, value: newValue }); - expect(callback).toHaveBeenCalled(); - }); - it('invokes the callback after value is set to equal value', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(initialValue, callback); - }); - rerender(); - expect(callback).toHaveBeenCalled(); - }); - it('does not invoke the callback if value does not update', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender(); - expect(callback).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts deleted file mode 100644 index c067e1747b4ff..0000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -export const useSetFieldValueWithCallback = ({ - field, - setFieldValue, - value, -}: { - field: string; - value: unknown; - setFieldValue: FormHook['setFieldValue']; -}) => { - const isWaitingRef = useRef(false); - const valueRef = useRef(); - const [callback, setCallback] = useState<() => void>(() => null); - - useEffect(() => { - if (isWaitingRef.current && value === valueRef.current) { - isWaitingRef.current = false; - valueRef.current = undefined; - callback(); - } - }, [value, callback]); - - return useCallback( - (v: unknown, cb: () => void) => { - setFieldValue(field, v); - - setCallback(() => cb); - valueRef.current = v; - isWaitingRef.current = true; - }, - [field, setFieldValue] - ); -}; diff --git a/x-pack/plugins/security_solution/public/contract_components.ts b/x-pack/plugins/security_solution/public/contract_components.ts index 8f5072f43f033..f7c255bcd34b8 100644 --- a/x-pack/plugins/security_solution/public/contract_components.ts +++ b/x-pack/plugins/security_solution/public/contract_components.ts @@ -11,6 +11,7 @@ import type { Observable } from 'rxjs'; export type ContractComponents = Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean }>; DashboardsLandingCallout: React.ComponentType<{}>; + EnablementModalCallout: React.ComponentType<{}>; }>; export type SetComponents = (components: ContractComponents) => void; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx index 079735aab3c48..c7ef28f5ed909 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx @@ -18,8 +18,8 @@ import type { FieldHook } from '../../../../shared_imports'; import { FilterBar } from '../../../../common/components/filter_bar'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import type { EqlOptions } from '../../../../../common/search_strategy'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import { useKibana } from '../../../../common/lib/kibana'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; import type { EqlQueryBarFooterProps } from './footer'; import { EqlQueryBarFooter } from './footer'; import { getValidationResults } from './validators'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx index 5b519cb43c841..75d3412705fde 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx @@ -11,11 +11,11 @@ import { debounceAsync } from '@kbn/securitysolution-utils'; import type { FormData, FieldConfig, ValidationFuncArg } from '../../../../shared_imports'; import { UseMultiFields } from '../../../../shared_imports'; import type { EqlFieldsComboBoxOptions, EqlOptions } from '../../../../../common/search_strategy'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import { queryRequiredValidatorFactory } from '../../../rule_creation_ui/validators/query_required_validator_factory'; import { eqlQueryValidatorFactory } from './eql_query_validator_factory'; import { EqlQueryBar } from './eql_query_bar'; import * as i18n from './translations'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; interface EqlQueryEditProps { path: string; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts index 54a0b3e3b6a65..284d0670dfbc3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts @@ -8,8 +8,8 @@ import { isEmpty } from 'lodash'; import type { FormData, ValidationError, ValidationFunc } from '../../../../shared_imports'; import { KibanaServices } from '../../../../common/lib/kibana'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import type { EqlOptions } from '../../../../../common/search_strategy'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; import type { EqlResponseError } from '../../../../common/hooks/eql/api'; import { EQL_ERROR_CODES, validateEql } from '../../../../common/hooks/eql/api'; import { EQL_VALIDATION_REQUEST_ERROR } from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx similarity index 71% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx index d0b4cee6752ad..933a45004fc70 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx @@ -5,21 +5,19 @@ * 2.0. */ -import React from 'react'; +import React, { memo } from 'react'; import { EuiPopover, EuiText, EuiButtonIcon, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import * as i18n from './translations'; - -import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { useBoolean } from '@kbn/react-hooks'; import { useKibana } from '../../../../common/lib/kibana'; +import * as i18n from './translations'; /** * Icon and popover that gives hint to users how to get started with ES|QL rules */ -const EsqlInfoIconComponent = () => { +export const EsqlInfoIcon = memo(function EsqlInfoIcon(): JSX.Element { const { docLinks } = useKibana().services; - - const [isPopoverOpen, , closePopover, togglePopover] = useBoolState(); + const [isPopoverOpen, { off: closePopover, on: togglePopover }] = useBoolean(false); const button = ( @@ -29,13 +27,13 @@ const EsqlInfoIconComponent = () => { @@ -45,8 +43,4 @@ const EsqlInfoIconComponent = () => { ); -}; - -export const EsqlInfoIcon = React.memo(EsqlInfoIconComponent); - -EsqlInfoIcon.displayName = 'EsqlInfoIcon'; +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx new file mode 100644 index 0000000000000..695a3d121c9a6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useMemo } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; +import type { DataViewBase } from '@kbn/es-query'; +import { debounceAsync } from '@kbn/securitysolution-utils'; +import type { FieldConfig } from '../../../../shared_imports'; +import { UseField } from '../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; +import { QueryBarField } from '../../../rule_creation_ui/components/query_bar_field'; +import { esqlQueryRequiredValidator } from './validators/esql_query_required_validator'; +import { esqlQueryValidatorFactory } from './validators/esql_query_validator_factory'; +import { EsqlInfoIcon } from './esql_info_icon'; +import * as i18n from './translations'; + +interface EsqlQueryEditProps { + path: string; + fieldsToValidateOnChange?: string | string[]; + dataView: DataViewBase; + required?: boolean; + loading?: boolean; + disabled?: boolean; + skipIdColumnCheck?: boolean; + onValidityChange?: (arg: boolean) => void; +} + +export const EsqlQueryEdit = memo(function EsqlQueryEdit({ + path, + fieldsToValidateOnChange, + dataView, + required = false, + loading = false, + disabled = false, + skipIdColumnCheck, + onValidityChange, +}: EsqlQueryEditProps): JSX.Element { + const queryClient = useQueryClient(); + const componentProps = useMemo( + () => ({ + isDisabled: disabled, + isLoading: loading, + indexPattern: dataView, + idAria: 'ruleEsqlQueryBar', + dataTestSubj: 'ruleEsqlQueryBar', + onValidityChange, + }), + [dataView, loading, disabled, onValidityChange] + ); + const fieldConfig: FieldConfig = useMemo( + () => ({ + label: i18n.ESQL_QUERY, + labelAppend: , + fieldsToValidateOnChange: fieldsToValidateOnChange + ? [path, fieldsToValidateOnChange].flat() + : undefined, + validations: [ + ...(required + ? [ + { + validator: esqlQueryRequiredValidator, + }, + ] + : []), + { + validator: debounceAsync( + esqlQueryValidatorFactory({ queryClient, skipIdColumnCheck }), + 300 + ), + }, + ], + }), + [required, path, fieldsToValidateOnChange, queryClient, skipIdColumnCheck] + ); + + return ( + + ); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts similarity index 76% rename from x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts index b8e1783dbe901..43eef8c21183d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts @@ -5,4 +5,5 @@ * 2.0. */ -export { ErrorStatePrompt, ErrorStateCallout } from './error_state_prompt'; +export * from './esql_query_edit'; +export * from './validators/error_codes'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts similarity index 62% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts index 8729f7b0dd3bc..9e48318c1c8bd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts @@ -7,8 +7,15 @@ import { i18n } from '@kbn/i18n'; +export const ESQL_QUERY = i18n.translate( + 'xpack.securitySolution.ruleManagement.fields.esqlQuery.label', + { + defaultMessage: 'ES|QL query', + } +); + export const ARIA_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoAriaLabel', + 'xpack.securitySolution.ruleManagement.fields.esqlQuery.ariaLabel', { defaultMessage: `Open help popover`, } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.ts new file mode 100644 index 0000000000000..5455dd1db5f0a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum ESQL_ERROR_CODES { + INVALID_ESQL = 'ERR_INVALID_ESQL', + INVALID_SYNTAX = 'ERR_INVALID_SYNTAX', + ERR_MISSING_ID_FIELD_FROM_RESULT = 'ERR_MISSING_ID_FIELD_FROM_RESULT', +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts new file mode 100644 index 0000000000000..d3f71eaaf5a86 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { fieldValidators, type FormData, type ValidationFunc } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import * as i18n from './translations'; + +export const esqlQueryRequiredValidator: ValidationFunc = ( + data +) => { + const { value } = data; + const esqlQuery = value.query.query as string; + + return fieldValidators.emptyField(i18n.ESQL_QUERY_VALIDATION_REQUIRED)({ + ...data, + value: esqlQuery, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts new file mode 100644 index 0000000000000..2799a606d3d9b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryClient } from '@tanstack/react-query'; +import { getESQLQueryColumns } from '@kbn/esql-utils'; +import type { FormData, ValidationFunc, ValidationFuncArg } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import { esqlQueryValidatorFactory } from './esql_query_validator_factory'; +import { ESQL_ERROR_CODES } from './error_codes'; + +jest.mock('@kbn/esql-utils', () => ({ + getESQLQueryColumns: jest.fn().mockResolvedValue([{ id: '_id' }]), +})); +jest.mock('../../../../../common/lib/kibana'); + +describe('esqlQueryValidator', () => { + describe('ES|QL query syntax', () => { + it.each([['incorrect syntax'], ['from test* metadata']])( + 'reports incorrect syntax in "%s"', + (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.INVALID_SYNTAX, + }) + ); + + it.each([ + ['from test* metadata _id'], + [ + 'FROM kibana_sample_data_logs | STATS total_bytes = SUM(bytes) BY host | WHERE total_bytes > 200000 | SORT total_bytes DESC | LIMIT 10', + ], + [ + `from packetbeat* metadata + _id + | limit 100`, + ], + [ + `FROM kibana_sample_data_logs | + STATS total_bytes = SUM(bytes) BY host | + WHERE total_bytes > 200000 | + SORT total_bytes DESC | + LIMIT 10`, + ], + ])('succeeds validation for correct syntax in "%s"', (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined() + ); + }); + + describe('METADATA operator validation', () => { + it.each([ + ['from test*'], + ['from metadata*'], + ['from test* | keep metadata'], + ['from test* | eval x="metadata _id"'], + ])('reports when METADATA operator is missing in a NON aggregating query "%s"', (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + }) + ); + + it.each([ + ['from test* metadata _id'], + ['from test* metadata _id, _index'], + ['from test* metadata _index, _id'], + ['from test* metadata _id '], + ['from test* metadata _id '], + ['from test* metadata _id | limit 10'], + [ + `from packetbeat* metadata + + _id + | limit 100`, + ], + ])( + 'succeeds validation when METADATA operator EXISTS in a NON aggregating query "%s"', + (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined() + ); + + it('succeeds validation when METADATA operator is missing in an aggregating query "from test* | stats c = count(*) by fieldA"', () => + expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* | stats c = count(*) by fieldA'), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined()); + }); + + describe('METADATA _id field validation for NON aggregating queries', () => { + it('reports when METADATA "_id" field is missing', () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: 'column1' }, { id: 'column2' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test*'), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + }); + }); + + it('succeeds validation when METADATA "_id" field EXISTS', async () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: '_id' }, { id: 'column1' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* metadata _id'), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined(); + }); + }); + + describe('METADATA _id field validation for aggregating queries', () => { + it('succeeds validation when METADATA operator with "_id" field is missing', () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: 'column1' }, { id: 'column2' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue( + 'from test* metadata someField | stats c = count(*) by fieldA' + ), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined(); + }); + }); + + describe('when getESQLQueryColumns fails', () => { + it('returns a validation error', () => { + // suppress the expected error messages + jest.spyOn(console, 'error').mockReturnValue(); + + getESQLQueryColumnsMock.mockRejectedValue(new Error('some error')); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* metadata _id'), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.INVALID_ESQL, + message: 'Error validating ES|QL: "some error"', + }); + }); + }); +}); + +type EsqlQueryValidatorArgs = ValidationFuncArg; + +const getESQLQueryColumnsMock = getESQLQueryColumns as jest.Mock; + +function createValidator(): ValidationFunc { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + }, + }, + }); + + return esqlQueryValidatorFactory({ queryClient }); +} + +function createEsqlQueryFieldValue(esqlQuery: string): Readonly { + return { query: { query: esqlQuery, language: 'esql' }, filters: [], saved_id: null }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts new file mode 100644 index 0000000000000..90cdaff14cc9b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryClient } from '@tanstack/react-query'; +import type { DatatableColumn } from '@kbn/expressions-plugin/common'; +import type { ESQLAstQueryExpression, ESQLCommandOption } from '@kbn/esql-ast'; +import { parse } from '@kbn/esql-ast'; +import { isAggregatingQuery } from '@kbn/securitysolution-utils'; +import { isColumnItem, isOptionItem } from '@kbn/esql-validation-autocomplete'; +import type { FormData, ValidationError, ValidationFunc } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import { fetchEsqlQueryColumns } from '../../../logic/esql_query_columns'; +import { ESQL_ERROR_CODES } from './error_codes'; +import * as i18n from './translations'; + +interface EsqlQueryValidatorFactoryParams { + queryClient: QueryClient; + /** + * This is a temporal fix to unlock prebuilt rule customization workflow + */ + skipIdColumnCheck?: boolean; +} + +export function esqlQueryValidatorFactory({ + queryClient, + skipIdColumnCheck, +}: EsqlQueryValidatorFactoryParams): ValidationFunc { + return async (...args) => { + const [{ value }] = args; + const esqlQuery = value.query.query as string; + + if (esqlQuery.trim() === '') { + return; + } + + try { + const { isEsqlQueryAggregating, hasMetadataOperator, errors } = parseEsqlQuery(esqlQuery); + + // Check if there are any syntax errors + if (errors.length) { + return constructSyntaxError(new Error(errors[0].message)); + } + + // non-aggregating query which does not have metadata, is not a valid one + if (!isEsqlQueryAggregating && !hasMetadataOperator) { + return { + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + message: i18n.ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR, + }; + } + + if (skipIdColumnCheck) { + return; + } + + const columns = await fetchEsqlQueryColumns({ + esqlQuery, + queryClient, + }); + + // for non-aggregating query, we want to disable queries w/o _id property returned in response + if (!isEsqlQueryAggregating && !hasIdColumn(columns)) { + return { + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + message: i18n.ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR, + }; + } + } catch (error) { + return constructValidationError(error); + } + }; +} + +function hasIdColumn(columns: DatatableColumn[]): boolean { + return columns.some(({ id }) => '_id' === id); +} + +/** + * check if esql query valid for Security rule: + * - if it's non aggregation query it must have metadata operator + */ +function parseEsqlQuery(query: string) { + const { root, errors } = parse(query); + const isEsqlQueryAggregating = isAggregatingQuery(root); + + return { + errors, + isEsqlQueryAggregating, + hasMetadataOperator: computeHasMetadataOperator(root), + }; +} + +/** + * checks whether query has metadata _id operator + */ +function computeHasMetadataOperator(astExpression: ESQLAstQueryExpression): boolean { + // Check whether the `from` command has `metadata` operator + const metadataOption = getMetadataOption(astExpression); + if (!metadataOption) { + return false; + } + + // Check whether the `metadata` operator has `_id` argument + const idColumnItem = metadataOption.args.find( + (fromArg) => isColumnItem(fromArg) && fromArg.name === '_id' + ); + if (!idColumnItem) { + return false; + } + + return true; +} + +function getMetadataOption(astExpression: ESQLAstQueryExpression): ESQLCommandOption | undefined { + const fromCommand = astExpression.commands.find((x) => x.name === 'from'); + + if (!fromCommand?.args) { + return undefined; + } + + // Check whether the `from` command has `metadata` operator + for (const fromArg of fromCommand.args) { + if (isOptionItem(fromArg) && fromArg.name === 'metadata') { + return fromArg; + } + } + + return undefined; +} + +function constructSyntaxError(error: Error): ValidationError { + return { + code: ESQL_ERROR_CODES.INVALID_SYNTAX, + message: error?.message + ? i18n.esqlValidationErrorMessage(error.message) + : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, + error, + }; +} + +function constructValidationError(error: Error): ValidationError { + return { + code: ESQL_ERROR_CODES.INVALID_ESQL, + message: error?.message + ? i18n.esqlValidationErrorMessage(error.message) + : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, + error, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts similarity index 72% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts index 4d6dde31fd5b4..21948a8863ec2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts @@ -7,28 +7,35 @@ import { i18n } from '@kbn/i18n'; +export const ESQL_QUERY_VALIDATION_REQUIRED = i18n.translate( + 'xpack.securitySolution.ruleManagement.esqlValidation.requiredError', + { + defaultMessage: 'An ES|QL query is required.', + } +); + export const ESQL_VALIDATION_UNKNOWN_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.unknownError', + 'xpack.securitySolution.ruleManagement.esqlValidation.unknownError', { defaultMessage: 'Unknown error while validating ES|QL', } ); export const esqlValidationErrorMessage = (message: string) => - i18n.translate('xpack.securitySolution.detectionEngine.esqlValidation.errorMessage', { + i18n.translate('xpack.securitySolution.ruleManagement.esqlValidation.errorMessage', { values: { message }, defaultMessage: 'Error validating ES|QL: "{message}"', }); export const ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError', + 'xpack.securitySolution.ruleManagement.esqlValidation.missingMetadataOperatorInQueryError', { defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index.`, } ); export const ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.missingIdFieldInQueryError', + 'xpack.securitySolution.ruleManagement.esqlValidation.missingIdFieldInQueryError', { defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index. In addition, the metadata properties (_id, _version, and _index) must be returned in the query response.`, } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts new file mode 100644 index 0000000000000..be4c53a31cef8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + FetchQueryOptions, + QueryClient, + QueryFunction, + QueryKey, +} from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import type { DatatableColumn } from '@kbn/expressions-plugin/common'; +import { getESQLQueryColumns } from '@kbn/esql-utils'; +import { KibanaServices } from '../../../common/lib/kibana'; + +const DEFAULT_STALE_TIME = 60 * 1000; + +interface FetchEsqlQueryColumnsParams { + esqlQuery: string; + queryClient: QueryClient; +} + +export async function fetchEsqlQueryColumns({ + esqlQuery, + queryClient, +}: FetchEsqlQueryColumnsParams): Promise { + const data = await queryClient.fetchQuery(createSharedTanstackQueryOptions(esqlQuery)); + + if (data instanceof Error) { + throw data; + } + + return data; +} + +interface UseEsqlQueryColumnsResult { + columns: DatatableColumn[]; + isLoading: boolean; +} + +export function useEsqlQueryColumns(esqlQuery: string): UseEsqlQueryColumnsResult { + const { data, isLoading } = useQuery({ + ...createSharedTanstackQueryOptions(esqlQuery), + retryOnMount: false, + refetchOnMount: false, + refetchOnWindowFocus: false, + }); + + return { columns: !data || data instanceof Error ? [] : data, isLoading }; +} + +function createSharedTanstackQueryOptions( + esqlQuery: string +): FetchQueryOptions { + return { + queryKey: [esqlQuery.trim()], + queryFn: queryEsqlColumnsFactory(esqlQuery), + staleTime: DEFAULT_STALE_TIME, + retry: false, + }; +} + +function queryEsqlColumnsFactory( + esqlQuery: string +): QueryFunction { + return async ({ signal }) => { + if (esqlQuery.trim() === '') { + return []; + } + + try { + return await getESQLQueryColumns({ + esqlQuery, + search: KibanaServices.get().data.search.search, + signal, + }); + } catch (e) { + return e; + } + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts deleted file mode 100644 index 808597ff36495..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.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 { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { parseEsqlQuery, computeHasMetadataOperator } from './esql_validator'; - -import { isAggregatingQuery } from '@kbn/securitysolution-utils'; - -jest.mock('@kbn/securitysolution-utils', () => ({ isAggregatingQuery: jest.fn() })); - -const isAggregatingQueryMock = isAggregatingQuery as jest.Mock; - -const getQeryAst = (query: string) => { - const { ast } = getAstAndSyntaxErrors(query); - return ast; -}; - -describe('computeHasMetadataOperator', () => { - it('should be false if query does not have operator', () => { - expect(computeHasMetadataOperator(getQeryAst('from test*'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata id'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from metadata*'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* | keep metadata'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* | eval x="metadata _id"'))).toBe( - false - ); - }); - it('should be true if query has operator', () => { - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id, _index'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _index, _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id | limit 10'))).toBe( - true - ); - expect( - computeHasMetadataOperator( - getQeryAst(`from packetbeat* metadata - - _id - | limit 100`) - ) - ).toBe(true); - - // still validates deprecated square bracket syntax - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id, _index'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _index, _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id | limit 10'))).toBe( - true - ); - expect( - computeHasMetadataOperator( - getQeryAst(`from packetbeat* metadata - - _id - | limit 100`) - ) - ).toBe(true); - }); -}); - -describe('parseEsqlQuery', () => { - it('returns isMissingMetadataOperator true when query is not aggregating and does not have metadata operator', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('from test*')).toEqual({ - errors: [], - isEsqlQueryAggregating: false, - isMissingMetadataOperator: true, - }); - }); - - it('returns isMissingMetadataOperator false when query is not aggregating and has metadata operator', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('from test* metadata _id')).toEqual({ - errors: [], - isEsqlQueryAggregating: false, - isMissingMetadataOperator: false, - }); - }); - - it('returns isMissingMetadataOperator false when query is aggregating', () => { - isAggregatingQueryMock.mockReturnValue(true); - - expect(parseEsqlQuery('from test*')).toEqual({ - errors: [], - isEsqlQueryAggregating: true, - isMissingMetadataOperator: false, - }); - - expect(parseEsqlQuery('from test* metadata _id')).toEqual({ - errors: [], - isEsqlQueryAggregating: true, - isMissingMetadataOperator: false, - }); - }); - - it('returns error when query is syntactically invalid', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('aaa bbbb ssdasd')).toEqual({ - errors: expect.arrayContaining([ - expect.objectContaining({ - message: - "SyntaxError: mismatched input 'aaa' expecting {'explain', 'from', 'row', 'show'}", - }), - ]), - isEsqlQueryAggregating: false, - isMissingMetadataOperator: true, - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts deleted file mode 100644 index c508676cae92c..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts +++ /dev/null @@ -1,160 +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 { isEmpty } from 'lodash'; -import type { QueryClient } from '@tanstack/react-query'; -import { isAggregatingQuery } from '@kbn/securitysolution-utils'; - -import type { ESQLAst } from '@kbn/esql-ast'; -import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { isColumnItem, isOptionItem } from '@kbn/esql-validation-autocomplete'; -import { KibanaServices } from '../../../common/lib/kibana'; - -import type { ValidationError, ValidationFunc } from '../../../shared_imports'; -import { isEsqlRule } from '../../../../common/detection_engine/utils'; -import type { DefineStepRule } from '../../../detections/pages/detection_engine/rules/types'; -import type { FieldValueQueryBar } from '../../rule_creation_ui/components/query_bar'; -import * as i18n from './translations'; -import { getEsqlQueryConfig } from './get_esql_query_config'; -export type FieldType = 'string'; - -export enum ERROR_CODES { - INVALID_ESQL = 'ERR_INVALID_ESQL', - INVALID_SYNTAX = 'ERR_INVALID_SYNTAX', - ERR_MISSING_ID_FIELD_FROM_RESULT = 'ERR_MISSING_ID_FIELD_FROM_RESULT', -} - -const constructValidationError = (error: Error) => { - return { - code: ERROR_CODES.INVALID_ESQL, - message: error?.message - ? i18n.esqlValidationErrorMessage(error.message) - : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, - error, - }; -}; - -const constructSyntaxError = (error: Error) => { - return { - code: ERROR_CODES.INVALID_SYNTAX, - message: error?.message - ? i18n.esqlValidationErrorMessage(error.message) - : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, - error, - }; -}; - -const getMetadataOption = (ast: ESQLAst) => { - const fromCommand = ast.find((astItem) => astItem.type === 'command' && astItem.name === 'from'); - - if (!fromCommand?.args) { - return undefined; - } - - // Check whether the `from` command has `metadata` operator - for (const fromArg of fromCommand.args) { - if (isOptionItem(fromArg) && fromArg.name === 'metadata') { - return fromArg; - } - } - - return undefined; -}; - -/** - * checks whether query has metadata _id operator - */ -export const computeHasMetadataOperator = (ast: ESQLAst) => { - // Check whether the `from` command has `metadata` operator - const metadataOption = getMetadataOption(ast); - if (!metadataOption) { - return false; - } - - // Check whether the `metadata` operator has `_id` argument - const idColumnItem = metadataOption.args.find( - (fromArg) => isColumnItem(fromArg) && fromArg.name === '_id' - ); - if (!idColumnItem) { - return false; - } - - return true; -}; - -/** - * form validator for ES|QL queryBar - */ -export const esqlValidator = async ( - ...args: Parameters -): Promise | void | undefined> => { - const [{ value, formData, customData }] = args; - const { query: queryValue } = value as FieldValueQueryBar; - const query = queryValue.query as string; - const { ruleType } = formData as DefineStepRule; - - const needsValidation = isEsqlRule(ruleType) && !isEmpty(query); - if (!needsValidation) { - return; - } - - try { - const queryClient = (customData.value as { queryClient: QueryClient | undefined })?.queryClient; - - const services = KibanaServices.get(); - const { isEsqlQueryAggregating, isMissingMetadataOperator, errors } = parseEsqlQuery(query); - - // Check if there are any syntax errors - if (errors.length) { - return constructSyntaxError(new Error(errors[0].message)); - } - - if (isMissingMetadataOperator) { - return { - code: ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, - message: i18n.ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR, - }; - } - - const columns = await queryClient?.fetchQuery( - getEsqlQueryConfig({ esqlQuery: query, search: services.data.search.search }) - ); - - if (columns && 'error' in columns) { - return constructValidationError(columns.error); - } - - // check whether _id field is present in response - const isIdFieldPresent = (columns ?? []).find(({ id }) => '_id' === id); - // for non-aggregating query, we want to disable queries w/o _id property returned in response - if (!isEsqlQueryAggregating && !isIdFieldPresent) { - return { - code: ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, - message: i18n.ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR, - }; - } - } catch (error) { - return constructValidationError(error); - } -}; - -/** - * check if esql query valid for Security rule: - * - if it's non aggregation query it must have metadata operator - */ -export const parseEsqlQuery = (query: string) => { - const { ast, errors } = getAstAndSyntaxErrors(query); - - const isEsqlQueryAggregating = isAggregatingQuery(ast); - - return { - errors, - isEsqlQueryAggregating, - // non-aggregating query which does not have metadata, is not a valid one - isMissingMetadataOperator: !isEsqlQueryAggregating && !computeHasMetadataOperator(ast), - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts deleted file mode 100644 index c7d4f9184f181..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts +++ /dev/null @@ -1,40 +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 { getESQLQueryColumns } from '@kbn/esql-utils'; -import type { ISearchGeneric } from '@kbn/search-types'; - -/** - * react-query configuration to be used to fetch ES|QL fields - * it sets limit in query to 0, so we don't fetch unnecessary results, only fields - */ -export const getEsqlQueryConfig = ({ - esqlQuery, - search, -}: { - esqlQuery: string | undefined; - search: ISearchGeneric; -}) => { - return { - queryKey: [(esqlQuery ?? '').trim()], - queryFn: async () => { - if (!esqlQuery) { - return null; - } - try { - const res = await getESQLQueryColumns({ - esqlQuery, - search, - }); - return res; - } catch (e) { - return { error: e }; - } - }, - staleTime: 60 * 1000, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx index 24ad5f4135a14..26c81f325ea18 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx @@ -72,6 +72,7 @@ import { ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, } from '../../../rule_creation/components/alert_suppression_edit'; import { THRESHOLD_ALERT_SUPPRESSION_ENABLED } from '../../../rule_creation/components/threshold_alert_suppression_edit'; +import type { FieldValueQueryBar } from '../query_bar_field'; const DescriptionListContainer = styled(EuiDescriptionList)` max-width: 600px; @@ -206,11 +207,12 @@ export const getDescriptionItem = ( indexPatterns?: DataViewBase ): ListItems[] => { if (field === 'queryBar') { - const filters = addFilterStateIfNotThere(get('queryBar.filters', data) ?? []); - const query = get('queryBar.query.query', data); - const savedId = get('queryBar.saved_id', data); - const savedQueryName = get('queryBar.title', data); - const ruleType: Type = get('ruleType', data); + const queryBar = get('queryBar', data) as FieldValueQueryBar; + const filters = addFilterStateIfNotThere(queryBar.filters ?? []); + const query = queryBar.query.query as string; + const savedId = queryBar.saved_id ?? ''; + const savedQueryName = queryBar.title; + const ruleType: Type = get('ruleType', data) as Type; const queryLabel = getQueryLabel(ruleType); return buildQueryBarDescription({ field, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts index e6a6b3d4a3d78..fa00914bced13 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts @@ -8,15 +8,6 @@ import { esqlToOptions } from './use_esql_fields_options'; describe('esqlToOptions', () => { - it('should return empty array if data is undefined', () => { - expect(esqlToOptions(undefined)).toEqual([]); - }); - it('should return empty array if data is null', () => { - expect(esqlToOptions(null)).toEqual([]); - }); - it('should return empty array if data has error', () => { - expect(esqlToOptions({ error: Error })).toEqual([]); - }); it('should transform all columns if fieldTYpe is not passed', () => { expect( esqlToOptions([ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts index b29d44c0b855f..f3a3128c8842e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts @@ -7,24 +7,12 @@ import { useMemo } from 'react'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; import type { DatatableColumn } from '@kbn/expressions-plugin/public'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { useEsqlQueryColumns } from '../../../rule_creation/logic/esql_query_columns'; -import { useQuery } from '@tanstack/react-query'; +type FieldType = 'string'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; - -import { getEsqlQueryConfig } from '../../../rule_creation/logic/get_esql_query_config'; -import type { FieldType } from '../../../rule_creation/logic/esql_validator'; - -export const esqlToOptions = ( - columns: { error: unknown } | DatatableColumn[] | undefined | null, - fieldType?: FieldType -) => { - if (columns && 'error' in columns) { - return []; - } - - const options = (columns ?? []).reduce>((acc, { id, meta }) => { +export const esqlToOptions = (columns: DatatableColumn[], fieldType?: FieldType) => { + const options = columns.reduce>((acc, { id, meta }) => { // if fieldType absent, we do not filter columns by type if (!fieldType || fieldType === meta.type) { acc.push({ label: id }); @@ -47,16 +35,11 @@ type UseEsqlFieldOptions = ( * fetches ES|QL fields and convert them to Combobox options */ export const useEsqlFieldOptions: UseEsqlFieldOptions = (esqlQuery, fieldType) => { - const kibana = useKibana<{ data: DataPublicPluginStart }>(); - - const { data: dataService } = kibana.services; - - const queryConfig = getEsqlQueryConfig({ esqlQuery, search: dataService.search.search }); - const { data, isLoading } = useQuery(queryConfig); + const { columns, isLoading } = useEsqlQueryColumns(esqlQuery ?? ''); const options = useMemo(() => { - return esqlToOptions(data, fieldType); - }, [data, fieldType]); + return esqlToOptions(columns, fieldType); + }, [columns, fieldType]); return { options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts new file mode 100644 index 0000000000000..c1f3150a3aa75 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FieldValueQueryBar } from './types'; + +export const DEFAULT_KQL_QUERY_FIELD_VALUE: Readonly = { + query: { query: '', language: 'kuery' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_THREAT_MATCH_KQL_QUERY_FIELD_VALUE: Readonly = { + query: { query: '*:*', language: 'kuery' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_EQL_QUERY_FIELD_VALUE: Readonly = { + query: { query: '', language: 'eql' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_ESQL_QUERY_FIELD_VALUE: Readonly = { + query: { query: '', language: 'esql' }, + filters: [], + saved_id: null, +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/index.ts new file mode 100644 index 0000000000000..07f6e408c5574 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './types'; +export * from './default_queries'; +export * from './query_field'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx index 7b757f8fc621d..190d10fe0a3b1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { QueryBarDefineRule } from '.'; +import { QueryBarField } from '.'; import { TestProviders, useFormFieldMock, @@ -74,7 +74,7 @@ describe('QueryBarDefineRule', () => { const { getByTestId } = render( - { const { queryByTestId } = render( - { const { getByTestId } = render( - ( title: savedQuery.attributes.title, }); -export const QueryBarDefineRule = ({ +export const QueryBarField = ({ defaultSavedQuery, dataTestSubj, field, @@ -85,7 +80,7 @@ export const QueryBarDefineRule = ({ resetToSavedQuery, onOpenTimeline, onSavedQueryError, -}: QueryBarDefineRuleProps) => { +}: QueryBarFieldProps) => { const { value: fieldValue, setValue: setFieldValue } = field as FieldHook; const [originalHeight, setOriginalHeight] = useState(-1); const [loadingTimeline, setLoadingTimeline] = useState(false); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/translations.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts similarity index 59% rename from x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts index 90d007d1d9411..9807be907209a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts @@ -5,5 +5,11 @@ * 2.0. */ -export { VersionMismatchPage } from './version_mismatch_page'; -export { VersionMismatchError } from './version_mismatch_error'; +import type { Filter, Query } from '@kbn/es-query'; + +export interface FieldValueQueryBar { + filters: Filter[]; + query: Query; + saved_id: string | null; + title?: string; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts index e6f9945737444..045e957c4e129 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts @@ -10,7 +10,7 @@ import type { EuiSelectOption } from '@elastic/eui'; import type { Type, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import * as i18n from './translations'; -import type { FieldValueQueryBar } from '../query_bar'; +import type { FieldValueQueryBar } from '../query_bar_field'; import type { TimeframePreviewOptions } from '../../../../detections/pages/detection_engine/rules/types'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx index 364f1b7705732..83aa6a114362a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; +import type { ChangeEvent } from 'react'; import { screen, fireEvent, render, within, act, waitFor } from '@testing-library/react'; import type { Type as RuleType } from '@kbn/securitysolution-io-ts-alerting-types'; import type { DataViewBase } from '@kbn/es-query'; @@ -42,13 +43,42 @@ import { addRelatedIntegrationRow, setVersion, } from '../../../rule_creation/components/related_integrations/test_helpers'; +import { useEsqlAvailability } from '../../../../common/hooks/esql/use_esql_availability'; +import { useMLRuleConfig } from '../../../../common/components/ml/hooks/use_ml_rule_config'; + +// Set the extended default timeout for all define rule step form test +jest.setTimeout(10 * 1000); // Mocks integrations jest.mock('../../../fleet_integrations/api'); + +const MOCKED_QUERY_BAR_TEST_ID = 'mockedQueryBar'; +const MOCKED_LANGUAGE_INPUT_TEST_ID = 'languageInput'; + +// Mocking QueryBar to avoid pulling and mocking a ton of dependencies jest.mock('../../../../common/components/query_bar', () => { return { - QueryBar: jest.fn(({ filterQuery }) => { - return
          {`${filterQuery.query} ${filterQuery.language}`}
          ; + QueryBar: jest.fn().mockImplementation(({ filterQuery, onSubmitQuery }) => { + const handleQueryChange = (event: ChangeEvent) => { + onSubmitQuery({ query: event.target.value, language: filterQuery.language }); + }; + + const handleLanguageChange = (event: ChangeEvent) => { + onSubmitQuery({ query: filterQuery.query, language: event.target.value }); + }; + + return ( +
          +